diff options
Diffstat (limited to 'ast/plot.c')
-rw-r--r-- | ast/plot.c | 32074 |
1 files changed, 32074 insertions, 0 deletions
diff --git a/ast/plot.c b/ast/plot.c new file mode 100644 index 0000000..368cb73 --- /dev/null +++ b/ast/plot.c @@ -0,0 +1,32074 @@ +/* +*class++ +* Name: +* Plot + +* Purpose: +* Provide facilities for 2D graphical output. + +* Constructor Function: +c astPlot +f AST_PLOT + +* Description: +* This class provides facilities for producing 2D graphical output. +* A Plot is a specialised form of FrameSet, in which the base +* Frame describes a "graphical" coordinate system and is +* associated with a rectangular plotting area in the underlying +* graphics system. This plotting area is where graphical output +* appears. It is defined when the Plot is created. +* +* The current Frame of a Plot describes a "physical" coordinate +* system, which is the coordinate system in which plotting +* operations are specified. The results of each plotting operation +* are automatically transformed into graphical coordinates so as +* to appear in the plotting area (subject to any clipping which +* may be in effect). +* +* Because the Mapping between physical and graphical coordinates +* may often be non-linear, or even discontinuous, most plotting +* does not result in simple straight lines. The basic plotting +* element is therefore not a straight line, but a geodesic curve +c (see astCurve, astGenCurve and astPolyCurve). A Plot also provides facilities for +c drawing markers or symbols (astMark), text (astText) and grid lines +c (astGridLine). It is also possible to draw curvilinear axes with +c optional coordinate grids (astGrid). +f (see AST_CURVE, AST_GENCURVE and AST_POLYCURVE). A Plot also provides facilities +f for drawing markers or symbols (AST_MARK), text (AST_TEXT) and grid +f lines (AST_GRIDLINE). It is also possible to draw curvilinear axes +f with optional coordinate grids (AST_GRID). +* A range of Plot attributes is available to allow precise control +* over the appearance of graphical output produced by these +c functions. +f routines. +* +* You may select different physical coordinate systems in which to +* plot (including the native graphical coordinate system itself) +* by selecting different Frames as the current Frame of a Plot, +* using its Current attribute. You may also set up clipping (see +c astClip) to limit the extent of any plotting you perform, and +f AST_CLIP) to limit the extent of any plotting you perform, and +* this may be done in any of the coordinate systems associated +* with the Plot, not necessarily the one you are plotting in. +* +* Like any FrameSet, a Plot may also be used as a Frame. In this +* case, it behaves like its current Frame, which describes the +* physical coordinate system. +* +* When used as a Mapping, a Plot describes the inter-relation +* between graphical coordinates (its base Frame) and physical +* coordinates (its current Frame). It differs from a normal +* FrameSet, however, in that an attempt to transform points which +* lie in clipped areas of the Plot will result in bad coordinate +* values (AST__BAD). + +* Inheritance: +* The Plot class inherits from the FrameSet class. + +* Attributes: +* In addition to those attributes common to all FrameSets, every +* Plot also has the following attributes: +* +* - Abbrev: Abbreviate leading fields? +* - Border: Draw a border around valid regions of a Plot? +* - Clip: Clip lines and/or markers at the Plot boundary? +* - ClipOp: Combine Plot clipping limits using a boolean OR? +* - Colour(element): Colour index for a Plot element +* - DrawAxes(axis): Draw axes for a Plot? +* - DrawTitle: Draw a title for a Plot? +* - Escape: Allow changes of character attributes within strings? +* - Edge(axis): Which edges to label in a Plot +* - Font(element): Character font for a Plot element +* - Gap(axis): Interval between linearly spaced major axis values +* - Grf: Select the graphics interface to use. +* - Grid: Draw grid lines for a Plot? +* - Invisible: Draw graphics in invisible ink? +* - LabelAt(axis): Where to place numerical labels for a Plot +* - LabelUnits(axis): Use axis unit descriptions in a Plot? +* - LabelUp(axis): Draw numerical Plot labels upright? +* - Labelling: Label and tick placement option for a Plot +* - LogGap(axis): Interval between logarithmically spaced major axis values +* - LogPlot(axis): Map the plot onto the screen logarithmically? +* - LogTicks(axis): Space the major tick marks logarithmically? +* - MajTickLen(axis): Length of major tick marks for a Plot +* - MinTickLen(axis): Length of minor tick marks for a Plot +* - MinTick(axis): Density of minor tick marks for a Plot +* - NumLab(axis): Draw numerical axis labels for a Plot? +* - NumLabGap(axis): Spacing of numerical axis labels for a Plot +* - Size(element): Character size for a Plot element +* - Style(element): Line style for a Plot element +* - TextLab(axis): Draw descriptive axis labels for a Plot? +* - TextLabGap(axis): Spacing of descriptive axis labels for a Plot +* - TickAll: Draw tick marks on all edges of a Plot? +* - TitleGap: Vertical spacing for a Plot title +* - Tol: Plotting tolerance +* - Width(element): Line width for a Plot element + +* Functions: +c In addition to those functions applicable to all FrameSets, the +c following functions may also be applied to all Plots: +f In addition to those routines applicable to all FrameSets, the +f following routines may also be applied to all Plots: +* +c - astBBuf: Begin a new graphical buffering context +c - astBorder: Draw a border around valid regions of a Plot +c - astBoundingBox: Returns a bounding box for previously drawn graphics +c - astClip: Set up or remove clipping for a Plot +c - astCurve: Draw a geodesic curve +c - astEBuf: End the current graphical buffering context +c - astGenCurve: Draw a generalized curve +c - astGetGrfContext: Get the graphics context for a Plot +c - astGrfPop: Retrieve previously saved graphics functions +c - astGrfPush: Save the current graphics functions +c - astGrfSet: Register a graphics routine for use by a Plot +c - astGrid: Draw a set of labelled coordinate axes +c - astGridLine: Draw a grid line (or axis) for a Plot +c - astMark: Draw a set of markers for a Plot +c - astPolyCurve: Draw a series of connected geodesic curves +c - astRegionOutline: Draw the outline of an AST Region +c - astText: Draw a text string for a Plot +f - AST_BBUF: Begin a new graphical buffering context +f - AST_BORDER: Draw a border around valid regions of a Plot +f - AST_BOUNDINGBOX: Returns a bounding box for previously drawn graphics +f - AST_CLIP: Set up or remove clipping for a Plot +f - AST_CURVE: Draw a geodesic curve +f - AST_EBUF: End the current graphical buffering context +f - AST_GENCURVE: Draw a generalized curve +f - AST_GETGRFCONTEXT: Get the graphics context for a Plot +f - AST_GRFPOP: Retrieve previously saved graphics functions +f - AST_GRFPUSH: Save the current graphics functions +f - AST_GRFSET: Register a graphics routine for use by the Plot class +f - AST_GRID: Draw a set of labelled coordinate axes +f - AST_GRIDLINE: Draw a grid line (or axis) for a Plot +f - AST_MARK: Draw a set of markers for a Plot +f - AST_POLYCURVE: Draw a series of connected geodesic curves +f - AST_REGIONOUTLINE: Draw the outline of an AST Region +f - AST_TEXT: Draw a text string for a Plot + +* Graphical Elements: +* The colour index, character font, character size, line style and +* line width used for plotting can be set independently for +* various elements of the graphical output produced by a Plot. +* The different graphical elements are identified by appending the +* strings listed below as subscripts to the Plot attributes +* Colour(element), Font(element), Size(element), Style(element) +* and Width(element). These strings are case-insensitive and +* unambiguous abbreviations may be used. Elements of the graphical +* output which relate to individual axes can be referred to either +* independently (e.g. "(Grid1)" and "(Grid2)" ) or together (e.g. +* "(Grid)"): +* +c - Axes: Axis lines drawn through tick marks using astGrid +f - Axes: Axis lines drawn through tick marks using AST_GRID +c - Axis1: Axis line drawn through tick marks on axis 1 using astGrid +f - Axis1: Axis line drawn through tick marks on axis 1 using AST_GRID +c - Axis2: Axis line drawn through tick marks on axis 2 using astGrid +f - Axis2: Axis line drawn through tick marks on axis 2 using AST_GRID +c - Border: The Plot border drawn using astBorder, astGrid or astRegionOutline +f - Border: The Plot border drawn using AST_BORDER, AST_GRID or AST_REGIONOUTLINE +c - Curves: Geodesic curves drawn using astCurve, astGenCurve or astPolyCurve +f - Curves: Geodesic curves drawn using AST_CURVE, AST_GENCURVE or AST_POLYCURVE +c - Grid: Grid lines drawn using astGridLine or astGrid +f - Grid: Grid lines drawn using AST_GRIDLINE or AST_GRID +c - Grid1: Grid lines which cross axis 1, drawn using astGridLine or astGrid +f - Grid1: Grid lines which cross axis 1, drawn using AST_GRIDLINE or AST_GRID +c - Grid2: Grid lines which cross axis 2, drawn using astGridLine or astGrid +f - Grid2: Grid lines which cross axis 2, drawn using AST_GRIDLINE or AST_GRID +c - Markers: Graphical markers (symbols) drawn using astMark +f - Markers: Graphical markers (symbols) drawn using AST_MARK +c - NumLab: Numerical axis labels drawn using astGrid +f - NumLab: Numerical axis labels drawn using AST_GRID +c - NumLab1: Numerical labels for axis 1 drawn using astGrid +f - NumLab1: Numerical labels for axis 1 drawn using AST_GRID +c - NumLab2: Numerical labels for axis 2 drawn using astGrid +f - NumLab2: Numerical labels for axis 2 drawn using AST_GRID +c - Strings: Text strings drawn using astText +f - Strings: Text strings drawn using AST_TEXT +c - TextLab: Descriptive axis labels drawn using astGrid +f - TextLab: Descriptive axis labels drawn using AST_GRID +c - TextLab1: Descriptive label for axis 1 drawn using astGrid +f - TextLab1: Descriptive label for axis 1 drawn using AST_GRID +c - TextLab2: Descriptive label for axis 2 drawn using astGrid +f - TextLab2: Descriptive label for axis 2 drawn using AST_GRID +c - Ticks: Tick marks (both major and minor) drawn using astGrid +f - Ticks: Tick marks (both major and minor) drawn using AST_GRID +c - Ticks1: Tick marks (both major and minor) for axis 1 drawn using astGrid +f - Ticks1: Tick marks (both major and minor) for axis 1 drawn using AST_GRID +c - Ticks2: Tick marks (both major and minor) for axis 2 drawn using astGrid +f - Ticks2: Tick marks (both major and minor) for axis 2 drawn using AST_GRID +c - Title: The Plot title drawn using astGrid +f - Title: The Plot title drawn using AST_GRID + +* Copyright: +* Copyright (C) 1997-2006 Council for the Central Laboratory of the +* Research Councils +* Copyright (C) 2009 Science & Technology Facilities Council. +* All Rights Reserved. + +* Licence: +* This program is free software: you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation, either +* version 3 of the License, or (at your option) any later +* version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General +* License along with this program. If not, see +* <http://www.gnu.org/licenses/>. + +* Authors: +* DSB: D.S. Berry (Starlink) +* RFWS: R.F. Warren-Smith (Starlink) + +* History: +* 18-SEP-1996 (DSB): +* Original version. +* 25-FEB-1997 (RFWS): +* Tidied all public prologues. +* 18-AUG-1997 (DSB): +* Changes made to ensure that the first label on each axis is +* never abbreviated, and to avoid segmentation violation when NumLab +* is set to zero. +* 1-SEP-1997 (DSB): +* astGetGap changed so that it returns the default value which will +* be used (instead of AST__BAD) if no value has been set for Gap. +* The Border attribute modified so that it is off (zero) by default. +* 19-SEP-1997 (DSB): +* o Check that something has been plotted before using the bounding +* box to determine title and label positions. +* o Fixed bug which caused a tick mark at the pole to be draw at +* a random angle. +* o The size of the increment used to determine the tangent to a grid +* line at the position to a label has been reduced to make sure the +* labls are drawn parallel to grid line. +* o Correct the logic for catering with reversed axes when determining +* the displacement of a label's reference point from the associated +* axis. +* o Corrected logic which determined if two numerical labels overlap. +* o Corrected logic for determining when to abbreviate numerical +* labels. +* o Use of strtok replaced by local function FindWord. +* o Correct logic which determines which side of the axis to draw +* tick marks when using interior labelling. +* o If the base Frame of the FrameSet supplied to astPlot has more +* than 2 axes, then use a sub-frame formed from the first two axes, +* instead of simply reporting an error. +* o If the current Frame of the Plot supplied to astGrid or +* astBorder has more than 2 axes, then use a sub-frame formed from +* the first two axes, instead of simply reporting an error. +* o Default for Border is now to draw the border if exterior +* Labelling is used, but not to draw it if interior labelling is +* used. +* o Public astGet function now returns actual used values for all +* attributes. Protected astGetXyz functions still return the requested +* value (which may differ from the used value), or the "unset" value +* if no value has been set for the attribute. +* o The defaults for Edge now depend on Labelling. If exterior +* labelling was requested but cannot be produced using defaults of +* Edge(1)=Bottom and Edge(2)=Left, then these default Edge values +* are swapped. If exterior labelling is still not possible, the +* original default Edge values are re-instated. +* o Unset attributes which use dynamic defaults are now flagged as +* "unhelpful" in the dump function. +* o Added attribute Escape which allows text strings to include +* escape sequences (see function GrText). This attribute and +* associated functionality is currently not available for use, search +* for all occurences of ENABLE-ESCAPE for instructions on how to +* enable the facilities. +* o Strings now used instead of integers to represent "choice" +* attributes externally (eg Edge and Labelling). +* 24-NOV-1997 (DSB): +* o Fixed bug in function Grid which caused units to be included in +* SkyFrame axis labels by default. +* o Replaced calls to DrawText by calls to astGText, and replaced +* references to "U" and "D" justifications by "T" and "B". This +* stops labels drifting to the bottom left when GAIA zooms. +* 23-MAR-1998 (DSB): +* Added extra checks on global status into routine Grid to avoid +* segmentation violations occuring due to null pointers being used. +* 10-JUN-1998 (DSB): +* Modify DrawTicks so that ticks are drawn closer to singularities +* than previously. Also normalise this constraint to the screen size +* rather than the length of a major tick mark. +* 28-OCT-1998 (DSB): +* o Added method astPolyCurve. +* o Extract the Current Frame from the Plot prior to using Frame +* methods such as astOffset, astNorm, etc. +* o PlotLabel modified to ensure labels are abbreviated even if +* they are next to the "root" label (i.e. the label with most +* trailing zeros). +* o Modified description of Width attribute. Width no longer gives +* the absolute line width in inches. Instead it is a scale factor, +* where 1.0 corresponds to a "typical thin line" on the device. +* o Modified LabelUnits attribute so that the default value is zero +* for SkyAxes and non-zero for other Axes. +* 10-DEC-1998 (DSB): +* Modified all calls to the "pow" maths function to avoid using +* literal constants as arguments. This seems to cause segmentation +* violations on some systems. +* 16-JUL-1999 (DSB): +* Fixed memory leaks in EdgeCrossings and EdgeLabels. +* 16-SEP-1999 (DSB): +* Avoid writing out clipping limits if they are undefined. +* 12-OCT-1999 (DSB): +* o Modified use of the NumLab attribute so that setting it to zero +* does not prevent exterior labels from being produced. +* o Allow length of tick marks to be specified separately for +* both axes. +* 13-OCT-2000 (DSB): +* o Purge zero length sections from CurveData structures. +* o Increase tolerance for edge labels from 0.0005 to 0.005. +* 9-JAN-2001 (DSB): +* o Change argument "in" for astMark and astPolyCurve from type +* "const double (*)[]" to "const double *". +* o Check success of astReadString before using the returned +* pointer. +* o Change method for choosing default LabelAt values to ignore +* values which produce no visible labels. +* 10-JAN-2001 (DSB): +* o Modified FindMajTick to choose the size of fillable holes in +* the axis range on the basis of the number of ticks on the axis. +* This avoids holes being visible in the displayed tick marks when +* using very small gaps. +* 22-MAY-2001 (DSB): +* Added a check when using interior labelling, to ensure that the +* most appropriate edges are used for text labels. +* 13-JUN-2001 (DSB): +* Added public method astGenCurve, astGrfSet, astGrfPop, astGrfPush. +* Made DrawAxes attribute axis specific. +* 4-JUL-2001 (DSB): +* The Crv function used to have a restriction that if *any* +* subsection was very short, then *none* of the subsections were +* subdivided. This meant that long subsections which needed +* subdividing were not subdivided if there was also a very short +* subsection. To get round this problem the restriction was changed +* to "if *all* subsections are very short then none are divided. +* This was implemented by changing dl2_min to dl2_max, and adding +* a check for very short segments (which are then not sub-divided). +* 16-AUG-2001 (DSB): +* Remove the check for very short segments introduced above, as it +* caused south pole tan projection to include some spurious lines. +* 20-SEP-2001 (DSB): +* - Initialize baseframe to NULL in astInitPlot (prevents segvios). +* - Modified astInitPlot to allow the "frame" argument to the astPlot +* constructor to be a Plot. +* 10-JAN-2002 (DSB): +* - Added axis-specific graphical elements "axis1", "axis2", etc. +* - FullForm returns a match without ambiguity if the test string +* matches an option exactly, including length. +* 31-JAN-2002 (DSB): +* - Added RejectOOB to reject tick marks which are not in their primary +* domain. +* 14-FEB-2002 (DSB): +* - Relaxed the conditions for equality within the EQUALS macro. +* Guard aginst no ticks being found. +* 18-FEB-2002 (DSB): +* - Make a permanent copy of any old axis format string in TickMarks. +* Previously a mere pointer into the astGet string buffer was stored, +* which could be over-written after many calls to astGet. +* - If a user specifies an axis format, use it whether or not it +* results in any identical adjacent labels. +* 4-MAR-2002 (DSB): +* - Made fairly extesive changes to the creation and use of tick +* mark values in order to circumvent problems with CAR projections, +* and "1 to many" mappings (such as 2D cartesian->polar). The +* policy now is that axis normalization is only performed when +* necessary (i.e. to create labels for display, etc). Tick mark +* values are stored and handled as non-normalized values as much as +* possible. +* 13-JUN-2002 (DSB): +* Modified Norm1 to prevent major tick value from being removed if +* the supplied reference value is out of bounds, resulting in the +* Mapping producing bad values +* 14-JUN-2002 (DSB): +* Re-wrote PlotLabels to improve abbreviation of labels and the +* choice of which labels not to print. +* 14-AUG-2002 (DSB): +* - Added method astBoundingBox. +* - Added attribute Invisible. +* - Correct handling of "axis specific" plot elements cuch as +* (Axis1), (Axis2), etc. +* 12-SEP-2002 (DSB): +* - Modified Map1 to remove slow normalization method (it is now +* faster but the changes result in some longer-than-needed grids +* lines when (e.g.) plotting pixel coordins in Polar coords). +* - Modified Axlot so that SkyFrames positions which are out of +* their normal ranges are not rejected by Map1. +* 10-OCT-2002 (DSB): +* grfAttrs:Modified to test element attributes explicitly using the +* relevant TestUse<attr> functions, instead of relying on the +* "GetUse<attr>" function returning the NO<attr> constant if not set. +* - Modified Axplot so that SkyFrames positions which are out of +* their normal ranges are not rejected by Map1. +* - Only use tick marks which are within the axis range given by the +* Bottom and Top Axis attributes. +* - Norm1: If the normalized current frame coords are bad, do not +* reinstate the original unnormalized values. For instance, current +* Frame values which are outside the valid domain of the projection +* should result in bad values when normalized, not the original +* good values. The original comment stated "If the normalization +* produced bad coords (e.g. as may happen if the supplied refernce +* value corresponds to a point on the line through the tick mark +* which is outside the valid region of the mapping) leave the original +* tick mark values unchanged". +* - GetTicks: Limit maxticks to be no less than 8. +* 8-JAN-2003 (DSB): +* - Changed private InitVtab method to protected astInitPlotVtab +* method. +* - Use private IsASkyFrame method in place of astIsASkyFrame. +* - Modify PlotLabels to excluding exponents when counting trailing +* zeros, and also to pad trailing fields with trailing zeros up to +* the max number of decimal places when estimating label priorities. +* - Modified Overlap to ensure that axis labels are speced by at +* least two spaces. +* 22-JAN-2003 (DSB): +* - Modified PlotLabels so that labels are rejected in a regular +* pattern rather than semi-random. +* - Modified the way PlotLabels abbreviates leading fields. +* - Introdued the skipbad parameter for the Crv function, in order +* to provide some degree of protection against the Crv algorithm +* skipping over small sections of valid coordinates (such as when +* a curve crosses the plot very close to a corner of the plot). +* 25-MAR-2003 (DSB): +* - Modified FindMajTicks to avoid losing tick marks when dealing +* with high precision data. +* 8-AUG-2003 (DSB): +* - Modified PlotLabels to ensure that the root label for the +* second axis is not omitted due to it overlapping a label from +* the first axis (a different root label is now chosen if this would +* be the case). +* - Modify FindMajTicks to avoid tick marks which should be at +* exactly zero being placed at some very small non-zero axis value. +* 22-OCT-2003 (DSB): +* - DrawTicks modified to correctly reset graphical attributes and +* pass on to the next axis if an axis has zero length major and minor +* tick marks. +* 9-JAN-2004 (DSB): +* DrawGrid: Report error if no grid curves can be drawn. +* AxPlot: Initialise returned CDATA structure before checking argument +* validity. +* GetTicks: Calculate the reference value on the other axis using +* function "Typical" rather than simply using the man of the supplied +* values (the supplied values may be clustered around 0 and 2*PI if the +* field is centred on the origin, resulting in the mean being at about +* 1.PI and therefore inappropriate). +* 13-JAN-2004 (DSB): +* - Added LogPlot attribute, and the facility for mapping the base +* coordinate system logarithmically onto the plotting area instead of +* linearly. +* - Added LogTicks attribute, and the facility for spacing the +* major tick marks logarithmically instead of linearly. +* - Added LogGap attribute, and the facility for storing separate +* gap sizes for linear and log tick spacing. +* 15-JAN-2004 (DSB): +* - Added LogLabel attribute. +* - Re-instated the inclusion of escape sequences in strings (see +* function GrText). +* 12-FEB-2004 (DSB): +* - RightVector: Corrected usage of chh and chv. +* - GQch and GScales: Check that values returned by grf module are +* usable. +* - DrawAxis: Extend axis section by one section (if possible) at +* each end (overcomes problems where the axis does not reach a pole). +* - DrawAxis: Check axis does not extend beyond a pole. +* - Labels: Correct logic of loop which plots interior labels +* (previously it missed out labels if there were only 3) +* - Allow for some rounding error in FindMajTicks when comparing an +* axis value with a loweror upper axis limit. +* 19-FEB-2004 (DSB): +* - Reduced the dynamic range restriction for log ticks from 2 decades +* to 1. +* - Temporarily clear any error status before re-instating the +* original Format in TickMarks. +* - Add LogTicks to the GetAttrib function so that the value of the +* LogTicks attribute can be got by the public. +* - Modify Crv to include a check that he vector scale has not +* changed much between adjacent segments. +* - Modify Crv so that a segment is only subdivided if at least +* half of the subsegments are longer than the shortest significant +* length. Also put a restriction on subdivision so that +* subdivision only occurs if the bounding box of the segment being +* sub-divided is smaller than the bounding box of its parent +* segment. +* 27-FEB-2004 (DSB): +* - Reduce the default Tol value from 0.001 to 0.01 in order to +* speed up curve drawing.. +* - Use 0.1*Tol in Boundary because the boundary tracing algorithm +* seems to produce much worse visible errors than it should do for a +* given Tol. +* 2-MAR-2004 (DSB): +* - Corrected handling of bounding boxes in Crv so that +* subdivision is allowed if the bounding box shrinks on only 1 axis +* (previously required shrinkage on both axes but this fails if +* all the points are on a horizontal or vertical line). +* - Modified FindMajTicks to use a better algorithm for finding an +* appropriate nfill value (previously logplot=1 axes could have +* unfilled holes at the high end). +* - Modified GetTicks so that FindMajTicks is not called +* repeatedly with the same gap size. +* - Modify AxPlot/Map1 so that the axis curve is sampled logarithmically +* if the corresponding axis is mapped logarithmically. +* 10-MAR-2004 (DSB): +* - Modified Typical to give less weight to vaalues close to the +* edges of the range covered by the plotting area. +* - Increased minimum angle between curve and edge required to +* create an edge label from 3 degs to 5 degs. +* - Modified PlotLabels to ignore duplicate adjacent labels which +* determining overlap of labels. +* 17-MAR-2004 (DSB): +* - Modified Typical to give normal weight to edge bins in +* histogram if these bins contain all the counts. +* - Modified DrawTicks to add extra minor ticks below first major +* tick value and above last major tick value. +* - Norm1 can reject usable tick mark values because of an +* inappropriate value being used on the other axis (i.e. one for +* which the position is undefined in grapics coords). Therfoer +* Norm1 has been modified to use 3 different reference values +* in an attempt to find one which gives good axis values. +* 25-AUG-2004 (DSB): +* - Correct handling of "fmt" pointer in TickMarks function (identified +* and reported by Bill Joye). +* 14-SEP-2004 (DSB): +* - In EdgeLabels change definition of "distinct labels". Used to +* be that labels were distinct if they had different formatted +* labels. Now they are distinct if they have different floating +* point numerical values. Fixes a bug reported by Micah Johnson. +* - TickMarks re-structured to optimise the precision (no. of digits) +* even if a value has been assigned for the Format attribute, but only +* if the format specifier includes a wildcard precision specifier. For +* instance, to get graphical separators a format must be specified +* which included the "g" flag. As things were, this would prevent +* the optimisation of the digits value. Can now use "dms.*g" to +* allow the number of digits to be optimised. +* 29-SEP-2004 (DSB): +* - In FindMajTicks, begin the process of increasing "nfill" from +* a value of zero rather than one (in many cases no filling is +* needed). +* - In GetTicks (linear tick marks section) ensure that 10 +* *different* gap sizes are used before giving up. Previously, the +* 10 tests could include duplicated gap values. +* 8-NOV-2004 (DSB): +* - In Norm1, try more alternative "other axis" values before +* accepting that a tick mark value cannot be normalised. +* 2-FEB-2005 (DSB): +* - Avoid using astStore to allocate more storage than is supplied +* in the "data" pointer. This can cause access violations since +* astStore will then read beyond the end of the "data" area. +* 15-MAR-2005 (DSB): +* - Modified GridLines to use appropriate algorithm for choosing +* start of grid lines in cases where one axis has logarithmic tick +* spacing and the other has linear tick spacing. +* 21-MAR-2005 (DSB): +* - Added the Clip attribute. +* 12-JUL-2005 (DSB): +* - Modified AxPlot so that Map1 only normalises if neither axis +* is a SkyAxis. Previously it normalised if either axis was not a +* SkyAxis. +* 7-DEC-2005 (DSB): +* Free memory allocated by calls to astReadString. +* 18-JAN-2006 (DSB) +* Add Abbrev attribute. +* 14-FEB-2006 (DSB) +* Correct EdgeLabels to use gap size rather than EQUAL macro when +* comparing label values. +* 17-FEB-2006 (DSB) +* Added escape sequences "%h+" and "%g+". +* 21-MAR-2006 (DSB) +* Added extra status checks in TickMarks. +* 18-MAY-2006 (DSB) +* Trans: use correct PointSet when tranforming to arbitrary +* clipping frame. +* 26-MAY-2006 (DSB) +* Added LabelAt to TestAttrib. +* 2-JUN-2006 (DSB) +* - In MAKE_GET2, return the set value if a value has been set +* without recalculating the defaults. +* - Fix bug that could cause segvio in Grid if clipping is used. +* 5-JUN-2006 (DSB) +* Do not change the box returned by astBoundBox as a consequence +* of calling astGetAttrib. +* 19-JUN-2006 (DSB) +* Changed the default line 0.0 from zero to 1.0. +* 22-JUN-2006 (DSB) +* Include axis textual labels and title in the bounding box +* created by AST_GRID and returned by AST_BOUNDINGBOX. +* 26-JUN-2006 (DSB) +* Set the Direction attribute in the base Frame of a Plot if an +* axis is reversed. +* 29-JUN-2006 (DSB) +* - Guard against astGap calls that reach a minimum gap size. +* - Sort out splitting of long axis labels (such as date/time +* strings produced by TimeFrames). +* 30-JUN-2006 (DSB) +* If abbreviating labels, display the last field for identical +* neighbours rather than the whole value. +* 10-JUL-2006 (DSB) +* Make astStripEscapes public so it can be used by the NDF library. +* 7-AUG-2006 (DSB) +* Increase the number of attempts to find a new gap size from 5 to +* 25 in GetTicks. +* 24-OCT-2006 (DSB) +* Add the ForceExterior attribute so that SPLAT can have external +* axes even if there are no usable horizontal axis ticks (as requested +* by PWD). Currently this attribute is not included in the public +* documentation, as it may cause problems. If it seems to work OK +* then it can be made public. +* 25-JAN-2006 (DSB) +* Do not draw ticks marks that start outside the bounds of the +* axis they are labelling. +* 27-FEB-2007 (DSB) +* - Change nominal Crv_scerr value from 5.0 to 1.5 (this avoids gaps +* in HPX grid plots being bridged by grid lines). +* - Double the dimension of the grid used by GoodGrid to avoid +* missing the pointy bits in a HPX projection. +* 17-MAY-2007 (DSB) +* Exclude corner positions when determining the range of axis +* values covered by the plot. This gives better default gap sizes. +* 11-JUN-2007 (DSB) +* Plug memory leaks. +* 20-JUN-2007 (DSB) +* - Add attribute GrfContext. +* - Pass the GrfContext attribute value to each external grf function. +* External code that uses the astGrfSet function must be changed +* so that the external grf functions registered using astGrfSet +* accept this new parameter. +* 21-JUN-2007 (DSB) +* - Change GrfContext to be an Object rather than an integer. +* 22-JUN-2007 (DSB) +* - Do not dump the GrfContext Object since it may cause an +* infinite dumping loop. +* - Allow a NULL vtab to be supplied when initialising a Plot +* structure. This causes the vtab defined locally within this +* class to be used so that the new object behaves as a simple Plot. +* 25-JUN-2007 (DSB) +* - Free the graphics context object when then the Plot is deleted. +* - Fix memory leak in FullForm. +* - Since the grfcontext object is only used by external code, store +* a public object identifier for it in the Plot structure rather +* than a true C pointer. +* 26-JUN-2007 (DSB) +* Honour the LabelUp attribute value even if labels are drawn +* around the edges of the plot. +* 28-JUN-2007 (DSB) +* - Make all axis attribute arrays 3 elements long rather than 2. +* - Add the protected methods astCopyPlotDefaults and astMirror. +* - Add public method astGetGrfContext, remove astSetGrfContext. +* - Fix memory leak. +* 6-SEP-2007 (DSB): +* Dump and load any user-specified tick mark values. +* 20-OCT-2009 (DSB): +* - Modify SplitValue so that it only splits long values if +* previous long values were split, or if the value contains a +* space. +* - Take account of zero height bounding boxes in UpdateConcat. +* - Correct Dump so that it dumps attributes for all available +* axes (2 for a Plot, 3 for a Plot3D). +* 12-JAN-2010 (DSB): +* Fix various memory leaks. +* 4-MAR-2011 (DSB): +* - Added grf functions BBuf and EBuf. +* - Added public method astBBuf and astEBuf. +* 23-AUG-2011 (DSB): +* - If exterior labelling was requested but would produced too +* few labels, only swap to interior labelling if doing so would +* allow more labels to be drawn (i.e. do not swap to interior if +* it does not gain us anything). +* - Slightly decrease the dynamic range of an axis needed to produce +* logarithmic ticks (this is to avoid problems with round errors). +* 6-OCT-2011 (DSB): +* - Prevent grf qch and scales functions being called lots of times +* during each drawing operation (since the information returned by +* these functions will not change during the course of a single drawing +* operation). +* 11-OCT-2011 (DSB): +* - Combine multiple continuous polylines into a single polyline +* before calling the grf polyline function. Reducing the number of +* calls to the underlying graphics system can make a big difference +* if the graphics system is written in an interpreted language +* such as python. +* - Take account of differing axis scales when rotating vectors by +* 90 degrees. +* 12-OCT-2011 (DSB): +* - Fix the change made yesterday to correct rotation of numerical axis +* rotations. I forgot that the astGText function in the grf module +* expects the up vector in equally scaled coords, not graphics coords. +* - Take account of unequal axis scales when working out the +* length of each grid curve. +* 15-OCT-2011 (DSB): +* Always check that the grf module implements the scales function +* before trying to invoke the scales function. +* 21-MAY-2012 (DSB): +* Correct text strings used to represent the "Labelling" attribute +* within dumps of a Plot. Previously they were reversed. +* 7-JUN-2012 (DSB): +* Speed up plotting of CmpRegion boundaries by splitting the +* CmpRegion up into a set of disjoint Regions, and plotting each +* one separately. +* 16-JUN-2014 (DSB): +* - Prevent seg fault in PlotLabels caused by accessing +* uninitialised "atext" field stored within purged labels. +* - Choose a label with non-negative priority as the fall-back root label. +* 17-APR-2015 (DSB): +* Added method astRegionOutline. +* 20-APR-2015 (DSB): +* Draw Regions with higher accuracy, because Regions (i.e. Polygons) +* can be very non-smooth. +*class-- +*/ + +/* Module Macros. */ +/* ============== */ +/* Set the name of the class we are implementing. This indicates to the header + files that define class interfaces that they should make "protected" + symbols available. */ +#define astCLASS Plot + +/* Values for constants used in this class. */ +#define CRV_NSEG 14 /* No. of curve segments drawn by function Crv */ +#define CRV_NPNT 15 /* CRV_NSEG plus one */ +#define CRV_MXENT 10 /* Max. no. of recursive entries into function Crv */ +#define MAJTICKS_OPT 10 /* Optimum number of major axiss or grid lines */ +#define MAJTICKS_MAX 14 /* Max. number of major ticks or grid lines */ +#define MAJTICKS_MIN 6 /* Min. number of major ticks or grid lines */ +#define EDGETICKS_DIM 100 /* No. of edge samples used to find tick marks */ +#define LEFT 0 /* Id for the left edge of the plotting area */ +#define TOP 1 /* Id for the top edge of the plotting area */ +#define RIGHT 2 /* Id for the right edge of the plotting area */ +#define BOTTOM 3 /* Id for the bottom edge of the plotting area */ +#define NOSTYLE -999 /* A value which represents a null Style value */ +#define NOWIDTH -99.9 /* A value which represents a null Style value */ +#define NOFONT -999 /* A value which represents a null Style value */ +#define NOCOLOUR -999 /* A value which represents a null Style value */ +#define NOSIZE -99.9 /* A value which represents a null Style value */ + +#if defined(THREAD_SAFE) +#define GLOBALS_PROTO , AstGlobals * +#define GLOBALS_ARG , AstGlobals *AST__GLOBALS +#define GLOBALS_NAME , AST__GLOBALS +#else +#define GLOBALS_PROTO +#define GLOBALS_ARG +#define GLOBALS_NAME +#endif + +/* +* +* Name: +* MAKE_CLEAR + +* Purpose: +* Implement a method to clear a single value in a multi-valued attribute. + +* Type: +* Private macro. + +* Synopsis: +* #include "plot.h" +* MAKE_CLEAR(attr,component,assign,nval) + +* Class Membership: +* Defined by the Plot class. + +* Description: +* This macro expands to an implementation of a private member function of +* the form: +* +* static void Clear<Attribute>( AstPlot *this, int axis ) +* +* and an external interface function of the form: +* +* void astClear<Attribute>_( AstPlot *this, int axis ) +* +* which implement a method for clearing a single value in a specified +* multi-valued attribute for an axis of a Plot. + +* Parameters: +* attr +* The name of the attribute to be cleared, as it appears in the function +* name (e.g. LabelAt in "astClearLabelAt"). +* component +* The name of the class structure component that holds the attribute +* value. +* assign +* An expression that evaluates to the value to assign to the component +* to clear its value. +* nval +* Specifies the number of values in the multi-valued attribute. The +* "axis" values supplied to the created function should be in the +* range zero to (nval - 1). If a value of 0 is supplied, the +* value of the Plot's Nin attribute is used instead. + +* Notes: +* - To avoid problems with some compilers, you should not leave any white +* space around the macro arguments. +* +*/ + +/* Define the macro. */ +#define MAKE_CLEAR(attr,component,assign,nval) \ +\ +/* Private member function. */ \ +/* ------------------------ */ \ +static void Clear##attr( AstPlot *this, int axis, int *status ) { \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return; \ +\ +/* Validate the axis index. */ \ + if( axis < 0 || axis >= ( nval ? nval : astGetNin( this ) ) ){ \ + astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ + #attr " - it should be in the range 1 to %d.", status, \ + "astClear" #attr, astGetClass( this ), \ + axis + 1, ( nval ? nval : astGetNin( this ) ) ); \ +\ +/* Assign the "clear" value. */ \ + } else { \ + this->component[ axis ] = (assign); \ + } \ +} \ +\ +/* External interface. */ \ +/* ------------------- */ \ +void astClear##attr##_( AstPlot *this, int axis, int *status ) { \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return; \ +\ +/* Invoke the required method via the virtual function table. */ \ + (**astMEMBER(this,Plot,Clear##attr))( this, axis, status ); \ +} + + +/* +* +* Name: +* MAKE_GET + +* Purpose: +* Implement a method to get a single value in a multi-valued attribute. + +* Type: +* Private macro. + +* Synopsis: +* #include "plot.h" +* MAKE_GET(attr,type,bad_value,assign,nval) + +* Class Membership: +* Defined by the Plot class. + +* Description: +* This macro expands to an implementation of a private member function of +* the form: +* +* static <Type> Get<Attribute>( AstPlot *this, int axis ) +* +* and an external interface function of the form: +* +* <Type> astGet<Attribute>_( AstPlot *this, int axis ) +* +* which implement a method for getting a single value from a specified +* multi-valued attribute for an axis of a Plot. + +* Parameters: +* attr +* The name of the attribute whose value is to be obtained, as it +* appears in the function name (e.g. Label in "astGetLabel"). +* type +* The C type of the attribute. +* bad_value +* A constant value to return if the global error status is set, or if +* the function fails. +* assign +* An expression that evaluates to the value to be returned. This can +* use the string "axis" to represent the zero-based value index. +* nval +* Specifies the number of values in the multi-valued attribute. The +* "axis" values supplied to the created function should be in the +* range zero to (nval - 1). If a value of 0 is supplied, the +* value of the Plot's Nin attribute is used instead. + +* Notes: +* - To avoid problems with some compilers, you should not leave any white +* space around the macro arguments. +* +*/ + +/* Define the macro. */ +#define MAKE_GET(attr,type,bad_value,assign,nval) \ +\ +/* Private member function. */ \ +/* ------------------------ */ \ +static type Get##attr( AstPlot *this, int axis, int *status ) { \ + type result; /* Result to be returned */ \ +\ +/* Initialise */ \ + result = (bad_value); \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return result; \ +\ +/* Validate the axis index. */ \ + if( axis < 0 || axis >= ( nval ? nval : astGetNin( this ) ) ){ \ + astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ + #attr " - it should be in the range 1 to %d.", status, \ + "astGet" #attr, astGetClass( this ), \ + axis + 1, ( nval ? nval : astGetNin( this ) ) ); \ +\ +/* Assign the result value. */ \ + } else { \ + result = (assign); \ + } \ +\ +/* Check for errors and clear the result if necessary. */ \ + if ( !astOK ) result = (bad_value); \ +\ +/* Return the result. */ \ + return result; \ +} \ +/* External interface. */ \ +/* ------------------- */ \ +type astGet##attr##_( AstPlot *this, int axis, int *status ) { \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return (bad_value); \ +\ +/* Invoke the required method via the virtual function table. */ \ + return (**astMEMBER(this,Plot,Get##attr))( this, axis, status ); \ +} + +/* +* +* Name: +* MAKE_SET + +* Purpose: +* Implement a method to set a single value in a multi-valued attribute +* for a Plot. + +* Type: +* Private macro. + +* Synopsis: +* #include "plot.h" +* MAKE_SET(attr,type,component,assign,nval) + +* Class Membership: +* Defined by the Plot class. + +* Description: +* This macro expands to an implementation of a private member function of +* the form: +* +* static void Set<Attribute>( AstPlot *this, int axis, <Type> value ) +* +* and an external interface function of the form: +* +* void astSet<Attribute>_( AstPlot *this, int axis, <Type> value ) +* +* which implement a method for setting a single value in a specified +* multi-valued attribute for a Plot. + +* Parameters: +* attr +* The name of the attribute to be set, as it appears in the function +* name (e.g. LabelAt in "astSetLabelAt"). +* type +* The C type of the attribute. +* component +* The name of the class structure component that holds the attribute +* value. +* assign +* An expression that evaluates to the value to be assigned to the +* component. +* nval +* Specifies the number of values in the multi-valued attribute. The +* "axis" values supplied to the created function should be in the +* range zero to (nval - 1). If a value of 0 is supplied, the +* value of the Plot's Nin attribute is used instead. + +* Notes: +* - To avoid problems with some compilers, you should not leave any white +* space around the macro arguments. +*- +*/ + +/* Define the macro. */ +#define MAKE_SET(attr,type,component,assign,nval) \ +\ +/* Private member function. */ \ +/* ------------------------ */ \ +static void Set##attr( AstPlot *this, int axis, type value, int *status ) { \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return; \ +\ +/* Validate the axis index. */ \ + if( axis < 0 || axis >= ( nval ? nval : astGetNin( this ) ) ){ \ + astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ + #attr " - it should be in the range 1 to %d.", status, \ + "astSet" #attr, astGetClass( this ), \ + axis + 1, ( nval ? nval : astGetNin( this ) ) ); \ +\ +/* Store the new value in the structure component. */ \ + } else { \ + this->component[ axis ] = (assign); \ + } \ +} \ +\ +/* External interface. */ \ +/* ------------------- */ \ +void astSet##attr##_( AstPlot *this, int axis, type value, int *status ) { \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return; \ +\ +/* Invoke the required method via the virtual function table. */ \ + (**astMEMBER(this,Plot,Set##attr))( this, axis, value, status ); \ +} + +/* +* +* Name: +* MAKE_TEST + +* Purpose: +* Implement a method to test if a single value has been set in a +* multi-valued attribute for a class. + +* Type: +* Private macro. + +* Synopsis: +* #include "plot.h" +* MAKE_TEST(attr,assign,nval) + +* Class Membership: +* Defined by the Plot class. + +* Description: +* This macro expands to an implementation of a private member function of +* the form: +* +* static int Test<Attribute>( AstPlot *this, int axis ) +* +* and an external interface function of the form: +* +* int astTest<Attribute>_( AstPlot *this, int axis ) +* +* which implement a method for testing if a single value in a specified +* multi-valued attribute has been set for a class. + +* Parameters: +* attr +* The name of the attribute to be tested, as it appears in the function +* name (e.g. LabelAt in "astTestLabelAt"). +* assign +* An expression that evaluates to 0 or 1, to be used as the returned +* value. This can use the string "axis" to represent the zero-based +* index of the value within the attribute. +* nval +* Specifies the number of values in the multi-valued attribute. The +* "axis" values supplied to the created function should be in the +* range zero to (nval - 1). If a value of 0 is supplied, the +* value of the Plot's Nin attribute is used instead. + +* Notes: +* - To avoid problems with some compilers, you should not leave any white +* space around the macro arguments. +*- +*/ + +/* Define the macro. */ +#define MAKE_TEST(attr,assign,nval) \ +\ +/* Private member function. */ \ +/* ------------------------ */ \ +static int Test##attr( AstPlot *this, int axis, int *status ) { \ + int result; /* Value to return */ \ +\ +/* Initialise */ \ + result = 0; \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return result; \ +\ +/* Validate the axis index. */ \ + if( axis < 0 || axis >= ( nval ? nval : astGetNin( this ) ) ){ \ + astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ + #attr " - it should be in the range 1 to %d.", status, \ + "astTest" #attr, astGetClass( this ), \ + axis + 1, ( nval ? nval : astGetNin( this ) ) ); \ +\ +/* Assign the result value. */ \ + } else { \ + result = (assign); \ + } \ +\ +/* Check for errors and clear the result if necessary. */ \ + if ( !astOK ) result = 0; \ +\ +/* Return the result. */ \ + return result; \ +} \ +/* External interface. */ \ +/* ------------------- */ \ +int astTest##attr##_( AstPlot *this, int axis, int *status ) { \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return 0; \ +\ +/* Invoke the required method via the virtual function table. */ \ + return (**astMEMBER(this,Plot,Test##attr))( this, axis, status ); \ +} + +/* +* +* Name: +* MAKE_GET3 + +* Purpose: +* Implement a method to get a single value in a multi-valued attribute. + +* Type: +* Private macro. + +* Synopsis: +* MAKE_GET3(attr,attr,type,bad_value,assign,nval) + +* Class Membership: +* Defined by the Plot class. + +* Description: +* This macro expands to an implementation of a private member function of +* the form: +* +* static <Type> Get<Attribute>( AstPlot *this, int axis ) +* +* which implements a method for getting a single value from a specified +* multi-valued attribute for an axis of a Plot. Note, no public +* interface function is created. +* +* The value returned is the value which would actually be used if +* astGrid was called with the current set of Plot attributes. This +* includes calculating any dynamic defaults which would be used, and is +* consequently rather slow. + +* Parameters: +* attr +* The name of the attribute whose value is to be obtained, as it +* appears in the function name (e.g. Label in "astGetLabel"). The +* string "Used" is added on to the front of the supplied value. +* type +* The C type of the attribute. +* bad_value +* A constant value to return if the global error status is set, or if +* the function fails. +* assign +* An expression that evaluates to the value to be returned. This can +* use the string "axis" to represent the zero-based value index. +* nval +* Specifies the number of values in the multi-valued attribute. The +* "axis" values supplied to the created function should be in the +* range zero to (nval - 1). If a value of 0 is supplied, the +* value of the Plot's Nin attribute is used instead. + +* Notes: +* - To avoid problems with some compilers, you should not leave any white +* space around the macro arguments. +* +*/ + +/* Define the macro. */ +#define MAKE_GET3(attr,type,bad_value,assign,nval) \ +\ +/* Private member function. */ \ +/* ------------------------ */ \ +static type GetUsed##attr( AstPlot *, int, int *status ); \ +static type GetUsed##attr( AstPlot *this, int axis, int *status ) { \ + type result; /* Result to be returned */ \ +\ +/* Initialise */ \ + result = (bad_value); \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return result; \ +\ +/* Validate the axis index. */ \ + if( axis < 0 || axis >= ( nval ? nval : astGetNin( this ) ) ){ \ + astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ + #attr " - it should be in the range 1 to %d.", status, \ + "astGetUsed" #attr, astGetClass( this ), \ + axis + 1, ( nval ? nval : astGetNin( this ) ) ); \ +\ +/* If the attribute is set, use its normal accessor. */\ + } else if( astTest##attr( this, axis ) ) {\ + result = astGet##attr( this, axis );\ +\ +/* Otherwise, re-calculate dynamic defaults by going through the motions of \ + drawing the grid. Nothing is actually drawn because we set the protected \ + attribute Ink to zero first. The calculated values are stored in the \ + Plot structure. */ \ + } else { \ + astSetInk( this, 0 ); \ + astGrid( this ); \ + astClearInk( this ); \ +\ +/* Assign the result value. */ \ + result = (assign); \ + } \ +\ +/* Check for errors and clear the result if necessary. */ \ + if ( !astOK ) result = (bad_value); \ +\ +/* Return the result. */ \ + return result; \ +} + +/* +* +* Name: +* MAKE_SET3 + +* Purpose: +* Implement a method to set a single value in a multi-valued attribute +* for a Plot. This is identical to MAKE_SET except that no external +* interface function is created. + +* Type: +* Private macro. + +* Synopsis: +* MAKE_SET3(attr,type,component,assign,nval) + +* Class Membership: +* Defined by the Plot class. + +* Description: +* This macro expands to an implementation of a private member function of +* the form: +* +* static void Set<Attribute>( AstPlot *this, int axis, <Type> value ) +* +* which implements a method for setting a single value in a specified +* multi-valued attribute for a Plot. + +* Parameters: + * attr +* The name of the attribute whose value is to be obtained, as it +* appears in the function name (e.g. Label in "astSetLabel"). The +* string "Used" is added on to the front of the supplied value. +* type +* The C type of the attribute. +* component +* The name of the class structure component that holds the attribute +* value. +* assign +* An expression that evaluates to the value to be assigned to the +* component. +* nval +* Specifies the number of values in the multi-valued attribute. The +* "axis" values supplied to the created function should be in the +* range zero to (nval - 1). If a value of 0 is supplied, the +* value of the Plot's Nin attribute is used instead. + +* Notes: +* - To avoid problems with some compilers, you should not leave any white +* space around the macro arguments. +*- +*/ + +/* Define the macro. */ +#define MAKE_SET3(attr,type,component,assign,nval) \ +\ +/* Private member function. */ \ +/* ------------------------ */ \ +static void SetUsed##attr( AstPlot *, int, type, int *status ); \ +static void SetUsed##attr( AstPlot *this, int axis, type value, int *status ) { \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return; \ +\ +/* Validate the axis index. */ \ + if( axis < 0 || axis >= ( nval ? nval : astGetNin( this ) ) ){ \ + astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ + #attr " - it should be in the range 1 to %d.", status, \ + "astSetUsed" #attr, astGetClass( this ), \ + axis + 1, ( nval ? nval : astGetNin( this ) ) ); \ +\ +/* Store the new value in the structure component. */ \ + } else { \ + this->component[ axis ] = (assign); \ + } \ +} + +/* +*+ +* Name: +* MAKE_GET2 + +* Purpose: +* Implement a method to get an attribute value for a class. + +* Type: +* Protected macro. + +* Synopsis: +* MAKE_GET2(class,attr,type,bad_value,assign) + +* Class Membership: +* Defined by the Plot class. + +* Description: +* This macro expands to an implementation of a private member function of +* the form: +* +* static <Type> GetUsed<Attr>( AstPlot *this ) +* +* which implement a method for getting a specified attribute value for a +* class. Note, no public interface function is created. +* +* The value returned is the value which would actually be used if +* astGrid was called with the current set of Plot attributes. This +* includes calculating any dynamic defaults which would be used, and is +* consequently rather slow. + +* Parameters: +* class +* The name (not the type) of the class to which the attribute belongs. +* attr +* The name of the attribute whose value is to be obtained, as it +* appears in the function name (e.g. Label in "astGetLabel"). The +* string "Used" is added on to the front of the supplied value. +* type +* The C type of the attribute. +* bad_value +* A constant value to return if the global error status is set, or if +* the function fails. +* assign +* An expression that evaluates to the value to be returned. + +* Notes: +* - To avoid problems with some compilers, you should not leave any white +* space around the macro arguments. +*- +*/ + +/* Define the macro. */ +#define MAKE_GET2(class,attr,type,bad_value,assign) \ +\ +/* Private member function. */ \ +/* ------------------------ */ \ +static type GetUsed##attr( Ast##class *, int *status ); \ +static type GetUsed##attr( Ast##class *this, int *status ) { \ + type result; /* Result to be returned */ \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return (bad_value); \ +\ +/* If the attribute is set, use its normal accessor. */\ + if( astTest##attr( this ) ) {\ + result = astGet##attr( this );\ +\ +/* Otherwise, re-calculate dynamic defaults by going through the motions of \ + drawing the grid. Nothing is actually drawn because we set the protected \ + attribute Ink to zero first. The calculated values are stored in the \ + Plot structure. */ \ + } else { \ + astSetInk( this, 0 ); \ + astGrid( this ); \ + astClearInk( this ); \ +\ +/* Assign the result value. */ \ + result = (assign); \ + } \ +\ +/* Check for errors and clear the result if necessary. */ \ + if ( !astOK ) result = (bad_value); \ +\ +/* Return the result. */ \ + return result; \ +} + +/* +*+ +* Name: +* MAKE_SET2 + +* Purpose: +* Implement a method to set an attribute value for a class. This +* is identical to astMAKE_SET except that it does not create an +* external interface function, and it does create a private function +* prototype. + +* Type: +* Protected macro. + +* Synopsis: +* MAKE_SET2(class,attr,type,component,assign) + +* Class Membership: +* Defined by the Plot class. + +* Description: +* This macro expands to an implementation of a private member function of +* the form: +* +* static void SetUsed<Attr>( AstPlot *this, <Type> value ) +* +* which implements a method for setting a specified attribute value for a +* class. + +* Parameters: +* class +* The name (not the type) of the class to which the attribute belongs. +* attr +* The name of the attribute to be set, as it appears in the function +* name (e.g. Label in "astSetLabel"). The string "Used" is added +* to the front. +* type +* The C type of the attribute. +* component +* The name of the class structure component that holds the attribute +* value. +* assign +* An expression that evaluates to the value to be assigned to the +* component. + +* Notes: +* - To avoid problems with some compilers, you should not leave +* any white space around the macro arguments. +*- +*/ + +/* Define the macro. */ +#define MAKE_SET2(class,attr,type,component,assign) \ +\ +/* Private member function. */ \ +/* ------------------------ */ \ +static void SetUsed##attr( Ast##class *, type, int *status ); \ +static void SetUsed##attr( Ast##class *this, type value, int *status ) { \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return; \ +\ +/* Store the new value in the structure component. */ \ + this->component = (assign); \ +} + + +/* Header files. */ +/* ============= */ +/* Interface definitions. */ +/* ---------------------- */ +#include "channel.h" /* I/O channels */ +#include "cmpmap.h" /* Compound mapping class */ + +#include "globals.h" /* Thread-safe global data access */ +#include "error.h" /* Error reporting facilities */ +#include "frame.h" /* Coordinate frame descriptions */ +#include "frameset.h" /* Parent FrameSet class */ +#include "grf.h" /* Low-level graphics interface */ +#include "memory.h" /* Memory allocation facilities */ +#include "object.h" /* Base Object class */ +#include "plot.h" /* Interface definition for this class */ +#include "pointset.h" /* Class holding lists of positions */ +#include "keymap.h" /* Hash maps */ +#include "skyaxis.h" /* Sky coordinate axes */ +#include "skyframe.h" /* Sky coordinate frames */ +#include "winmap.h" /* Scale and shift mappings */ +#include "mathmap.h" /* Algebraic mappings */ +#include "wcsmap.h" /* FITS-WCS projectsions */ +#include "unitmap.h" /* Unit mappings */ +#include "permmap.h" /* Axis permutations */ +#include "region.h" /* Frame regions */ +#include "globals.h" /* Thread-safe global data access */ + + +/* Error code definitions. */ +/* ----------------------- */ +#include "ast_err.h" /* AST error codes */ + +/* C header files. */ +/* --------------- */ +#include <ctype.h> +#include <float.h> +#include <math.h> +#include <stddef.h> +#include <stdio.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> + +/* Module Type Definitions */ +/* ======================= */ +typedef struct LabelList { + double index; + char *text; + double x; + double y; + char *just; + double upx; + double upy; + double val; + int priority; + const char *atext; + int saved_prio; +} LabelList; + +/* Structure to hold static data used internally within the Crv function. */ +typedef struct CrvStatics { + double *pdl2; /* Pointer to next squared segment length */ + double *pdx; /* Pointer to next segment X increment */ + double *pdy; /* Pointer to next segment Y increment */ + double cosang; /* Cosine of angle between adjacent segments */ + double d0; /* Distance to start of first sub-segment */ + double delta; /* Distance between adjacent sub-segments */ + double dl; /* Segment length in graphics coordinates */ + double dll; /* Segment length for previous segment */ + double last_x; /* Graphics X at the end of the previous segment */ + double last_y; /* Graphics Y at the end of the previous segment */ + double limit2; /* Shortest acceptable squared segment length */ + double t1; /* Increment in X */ + double t2; /* Increment in Y */ + double t3; /* Squared segment length */ + double vx; /* X component of unit vector for current segment */ + double vxl; /* X component of unit vector for previous segment */ + double vy; /* Y component of unit vector for current segment */ + double vyl; /* Y component of unit vector for previous segment */ + int *seg0; /* Pointer to current segment OK flag */ + int *segm; /* Pointer to previous segment OK flag */ + int *segp; /* Pointer to next segment OK flag */ + int all_bad; /* Are all supplied positions bad or clipped? */ + int el; /* Total sub-segment count */ + int j; /* Sub-segment index */ + int last_ok; /* Was the previous position defined? */ + int nel; /* Total number of sub-segments */ + int nlong; /* No.of segments longer than limit2 */ + int nseg; /* Number of segments being sub-divided */ + int nshort; /* No.of segments shorter than limit2 */ + +#ifdef CRV_TRACE + int levels[100]; +#endif + +} CrvStatics; + +/* Structure to hold static data used internally within the Crv function. */ +typedef struct GetTicksStatics { + AstFrame *frame; /* Pointer to the current Frame */ + AstMapping *map; /* Pointer to Base->Current Mapping */ + AstPointSet *pset; /* Pointer to a PointSet holding physical coords */ + double **ptr; /* Pointer to physical coordinate values */ + double defgaps[ 2 ]; /* Initial test gaps for each axis */ + double typval[ 2 ]; /* Typical value on each axis */ + double width[ 2 ]; /* Range of used axis values */ + int maxticks; /* Max. number of ticks on each axis */ + int mintick; /* Min. number of ticks on each axis */ + int ngood[ 2 ]; /* No. of good physical values on each axis */ + int bad; /* Were any bad pixels found? */ +} GetTicksStatics; + +/* Structure to hold static data used internally within the EdgeCrossings + function. */ +typedef struct EdgeCrossingsStatics { + AstFrame *frame; /* Pointer to current Frame in Plot */ + AstPointSet *pset1; /* Graphics cooords at edge samples */ + AstPointSet *pset2; /* Physical cooords at edge samples */ + AstPointSet *pset4; /* Graphics cooords at offset edge samples */ + double **ptr1; /* Pointer to graphics coord. data */ + double **ptr2; /* Pointer to physical coord. data */ + double **ptr4; /* Pointer to graphics coord. data */ + double edgehi; /* High bound on varying graphics axis */ + double edgelo; /* Low bound on varying graphics axis */ + double edgeval; /* Constant graphics axis value along edge */ + double limit; /* Three times the RMS step size */ + int dim; /* Extended number of samples */ + int edgeax; /* Graphics axis to which edgeval refers */ + int paxis; /* Axis used in first invocation */ + int pedge; /* Edge used in first invocation */ +} EdgeCrossingsStatics; + + +/* Structure to hold static data used internally within the Map1 + function. */ +typedef struct Map1Statics { + AstPointSet *pset1; /* PointSet holding physical coords */ + AstPointSet *pset2; /* PointSet holding graphics coords */ + double **ptr1; /* Pointer to physical coord data */ + double *pax; /* Pointer to start of axis data */ + double *ptr2[ 2 ]; /* Pointers to graphics coord data */ + double *work1; /* Pointer to work space */ + double *work2; /* Pointer to work space */ + double axorig; /* Distance offset */ + double axscale; /* Distance scale */ + int neg; /* Negate axis values? */ + int nl; /* No. of points in pset1 and pset2 */ +} Map1Statics; + +/* Structure to hold static data used internally within the Map2 + function. */ +typedef struct Map2Statics { + AstPointSet *pset1; /* PointSet holding graphics coords */ + AstPointSet *pset2; /* PointSet holding physical coords */ + double **ptr2; /* Pointer to physical coord data */ + double *ptr1[ 2 ]; /* Pointers to graphics coord data */ + int nl; /* No. of points in pset1 and pset2 */ +} Map2Statics; + +/* Structure to hold static data used internally within the Map3 + function. */ +typedef struct Map3Statics { + AstPointSet *pset1; /* PointSet holding physical coords */ + AstPointSet *pset2; /* PointSet holding graphics coords */ + double **ptr1; /* Pointer to physical coord data */ + double *ptr2[ 2 ]; /* Pointers to graphics coord data */ + int nc; /* No. of physical axes */ + int nl; /* No. of points in pset1 and pset2 */ + double *pos; /* Pointer to memory for a single position */ +} Map3Statics; + +/* Structure to hold static data used internally within the Map4 + function. */ +typedef struct Map4Statics { + AstPointSet *pset1; /* PointSet holding distances */ + AstPointSet *pset2; /* PointSet holding physical coords */ + AstPointSet *pset3; /* PointSet holding graphics coords */ + int nl; /* No. of points in pset1 and pset2 */ +} Map4Statics; + +/* Structure to hold static data used internally within the Map5 + function. */ +typedef struct Map5Statics { + AstPointSet *pset1; /* PointSet holding physical coords */ + AstPointSet *pset2; /* PointSet holding graphics coords */ + double **ptr1; /* Pointer to physical coord data */ + double *ptr2[ 2 ]; /* Pointers to graphics coord data */ + int nl; /* No. of points in pset1 and pset2 */ +} Map5Statics; + +/* Structure to hold information about tick marks for a single axis. */ +typedef struct TickInfo{ + int nmajor; /* No. of major tick marks */ + int nminor; /* No. of minor tick marks */ + double *ticks; /* Pointer to array of major tick mark values */ + double *minticks; /* Pointer to array of minor tick mark values */ + char **labels; /* Pointer to array of major tick mark labels */ + double *start; /* Start pos'n on other axis for each curve section */ + double *length; /* Length on other axis of each curve section */ + int nsect; /* No. of sections in curve */ + char *fmt; /* Pointer to format string used to create labels */ + double gap; /* The gap between major ticks */ +} TickInfo; + +/* Module Variables. */ +/* ================= */ + +/* Address of this static variable is used as a unique identifier for + member of this class. */ +static int class_check; + +/* Pointers to parent class methods which are extended by this class. */ +static void (* parent_removeframe)( AstFrameSet *, int, int * ); +static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, + AstPointSet *, int * ); +static const char *(* parent_getattrib)( AstObject *, const char *, int * ); +static int (* parent_testattrib)( AstObject *, const char *, int * ); +static void (* parent_clearattrib)( AstObject *, const char *, int * ); +static void (* parent_setattrib)( AstObject *, const char *, int * ); + +#if defined(THREAD_SAFE) +static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); +#endif + +/* Strings giving the label for the graphics items corresponding to + AST__BORDER_ID, AST__GRIDLINE_ID, etc. */ +static char *GrfLabels = "Border Curves Title Markers Strings Axis1 Axis2 Axis3 " + "NumLab1 NumLab2 NumLab3 TextLab1 TextLab2 TextLab3 " + "Ticks1 Ticks2 Ticks3 Grid1 Grid2 Grid3 Axes NumLab " + "TextLab Grid Ticks"; + +/* Text values used to represent edges externally. */ +static const char *xedge[4] = { "left", "top", "right", "bottom" }; + +/* Text values used to represent Labelling externally. */ +static const char *xlbling[2] = { "exterior", "interior" }; + +/* Define macros for accessing each item of thread specific global data. */ +#ifdef THREAD_SAFE + +/* Define how to initialise thread-specific globals. */ +#define GLOBAL_inits \ + globals->Class_Init = 0; \ + globals->GrfAttrs_nesting_t = 0; \ + globals->Crv_nent_t = 0; \ + globals->Box_lbnd_t[ 0 ] = FLT_MAX; \ + globals->Box_ubnd_t[ 0 ] = FLT_MIN; \ + globals->Boxp_lbnd_t[ 0 ] = FLT_MAX; \ + globals->Boxp_ubnd_t[ 0 ] = FLT_MIN; \ + globals->Box_lbnd_t[ 1 ] = FLT_MAX; \ + globals->Box_ubnd_t[ 1 ] = FLT_MIN; \ + globals->Boxp_lbnd_t[ 1 ] = FLT_MAX; \ + globals->Boxp_ubnd_t[ 1 ] = FLT_MIN; \ + globals->Boxp_freeze_t = 0; \ + globals->Map1_plot_t = NULL; \ + globals->Map1_map_t = NULL; \ + globals->Map1_frame_t = NULL; \ + globals->Map1_origin_t = NULL; \ + globals->Map1_statics_t = NULL; \ + globals->Map2_plot_t = NULL; \ + globals->Map2_map_t = NULL; \ + globals->Map2_statics_t = NULL; \ + globals->Map3_plot_t = NULL; \ + globals->Map3_map_t = NULL; \ + globals->Map3_frame_t = NULL; \ + globals->Map3_origin_t = NULL; \ + globals->Map3_end_t = NULL; \ + globals->Map3_statics_t = NULL; \ + globals->Map4_plot_t = NULL; \ + globals->Map4_map_t = NULL; \ + globals->Map4_umap_t = NULL; \ + globals->Map4_statics_t = NULL; \ + globals->Map5_plot_t = NULL; \ + globals->Map5_region_t = NULL; \ + globals->Map5_map_t = NULL; \ + globals->Map5_statics_t = NULL; \ + globals->Poly_n_t = 0; \ + globals->Poly_x_t = NULL; \ + globals->Poly_y_t = NULL; \ + globals->Poly_npoly_t = 0; \ + globals->Poly_np_t = NULL; \ + globals->Poly_xp_t = NULL; \ + globals->Poly_yp_t = NULL; \ + globals->Curve_data_t.nbrk = -1; \ + globals->GetAttrib_Buff[ 0 ] = 0; \ + globals->SplitValue_Buff[ 0 ] = 0; \ + globals->StripEscapes_Buff[ 0 ] = 0; \ + globals->Grf_chv_t = AST__BAD; \ + globals->Grf_chh_t = AST__BAD; \ + globals->Grf_alpha_t = 0.0; \ + globals->Grf_beta_t = 0.0; + +/* Create the function that initialises global data for this module. */ +astMAKE_INITGLOBALS(Plot) + +/* Define macros for accessing each item of thread specific global data. */ +#define class_init astGLOBAL(Plot,Class_Init) +#define class_vtab astGLOBAL(Plot,Class_Vtab) +#define grfattrs_nesting astGLOBAL(Plot,GrfAttrs_nesting_t) +#define grfattrs_attrs astGLOBAL(Plot,GrfAttrs_attrs_t) +#define Crv_limit astGLOBAL(Plot,Crv_limit_t) +#define Crv_scerr astGLOBAL(Plot,Crv_scerr_t) +#define Crv_tol astGLOBAL(Plot,Crv_tol_t) +#define Crv_ux0 astGLOBAL(Plot,Crv_ux0_t) +#define Crv_uy0 astGLOBAL(Plot,Crv_uy0_t) +#define Crv_vxl astGLOBAL(Plot,Crv_vxl_t) +#define Crv_vyl astGLOBAL(Plot,Crv_vyl_t) +#define Crv_xhi astGLOBAL(Plot,Crv_xhi_t) +#define Crv_xl astGLOBAL(Plot,Crv_xl_t) +#define Crv_xlo astGLOBAL(Plot,Crv_xlo_t) +#define Crv_yhi astGLOBAL(Plot,Crv_yhi_t) +#define Crv_yl astGLOBAL(Plot,Crv_yl_t) +#define Crv_ylo astGLOBAL(Plot,Crv_ylo_t) +#define Crv_vxbrk astGLOBAL(Plot,Crv_vxbrk_t) +#define Crv_vybrk astGLOBAL(Plot,Crv_vybrk_t) +#define Crv_xbrk astGLOBAL(Plot,Crv_xbrk_t) +#define Crv_ybrk astGLOBAL(Plot,Crv_ybrk_t) +#define Crv_len astGLOBAL(Plot,Crv_len_t) +#define Crv_ink astGLOBAL(Plot,Crv_ink_t) +#define Crv_nbrk astGLOBAL(Plot,Crv_nbrk_t) +#define Crv_nent astGLOBAL(Plot,Crv_nent_t) +#define Crv_out astGLOBAL(Plot,Crv_out_t) +#define Crv_clip astGLOBAL(Plot,Crv_clip_t) +#define Crv_map astGLOBAL(Plot,Crv_map_t) +#define Box_lbnd astGLOBAL(Plot,Box_lbnd_t) +#define Box_ubnd astGLOBAL(Plot,Box_ubnd_t) +#define Boxp_lbnd astGLOBAL(Plot,Boxp_lbnd_t) +#define Boxp_ubnd astGLOBAL(Plot,Boxp_ubnd_t) +#define Boxp_freeze astGLOBAL(Plot,Boxp_freeze_t) +#define Poly_x astGLOBAL(Plot,Poly_x_t) +#define Poly_y astGLOBAL(Plot,Poly_y_t) +#define Poly_n astGLOBAL(Plot,Poly_n_t) +#define Poly_xp astGLOBAL(Plot,Poly_xp_t) +#define Poly_yp astGLOBAL(Plot,Poly_yp_t) +#define Poly_np astGLOBAL(Plot,Poly_np_t) +#define Poly_npoly astGLOBAL(Plot,Poly_npoly_t) +#define Map1_ncoord astGLOBAL(Plot,Map1_ncoord_t) +#define Map1_plot astGLOBAL(Plot,Map1_plot_t) +#define Map1_map astGLOBAL(Plot,Map1_map_t) +#define Map1_frame astGLOBAL(Plot,Map1_frame_t) +#define Map1_origin astGLOBAL(Plot,Map1_origin_t) +#define Map1_length astGLOBAL(Plot,Map1_length_t) +#define Map1_axis astGLOBAL(Plot,Map1_axis_t) +#define Map1_statics astGLOBAL(Plot,Map1_statics_t) +#define Map1_norm astGLOBAL(Plot,Map1_norm_t) +#define Map1_log astGLOBAL(Plot,Map1_log_t) +#define Map2_ncoord astGLOBAL(Plot,Map2_ncoord_t) +#define Map2_plot astGLOBAL(Plot,Map2_plot_t) +#define Map2_map astGLOBAL(Plot,Map2_map_t) +#define Map2_x0 astGLOBAL(Plot,Map2_x0_t) +#define Map2_y0 astGLOBAL(Plot,Map2_y0_t) +#define Map2_deltax astGLOBAL(Plot,Map2_deltax_t) +#define Map2_deltay astGLOBAL(Plot,Map2_deltay_t) +#define Map2_statics astGLOBAL(Plot,Map1_statics_t) +#define Map3_ncoord astGLOBAL(Plot,Map3_ncoord_t) +#define Map3_plot astGLOBAL(Plot,Map3_plot_t) +#define Map3_map astGLOBAL(Plot,Map3_map_t) +#define Map3_frame astGLOBAL(Plot,Map3_frame_t) +#define Map3_origin astGLOBAL(Plot,Map3_origin_t) +#define Map3_end astGLOBAL(Plot,Map3_end_t) +#define Map3_scale astGLOBAL(Plot,Map3_scale_t) +#define Map3_statics astGLOBAL(Plot,Map3_statics_t) +#define Map4_ncoord astGLOBAL(Plot,Map4_ncoord_t) +#define Map4_plot astGLOBAL(Plot,Map4_plot_t) +#define Map4_map astGLOBAL(Plot,Map4_map_t) +#define Map4_umap astGLOBAL(Plot,Map4_umap_t) +#define Map4_statics astGLOBAL(Plot,Map4_statics_t) +#define Map5_plot astGLOBAL(Plot,Map5_plot_t) +#define Map5_region astGLOBAL(Plot,Map5_region_t) +#define Map5_map astGLOBAL(Plot,Map5_map_t) +#define Map5_ncoord astGLOBAL(Plot,Map5_ncoord_t) +#define Map5_statics astGLOBAL(Plot,Map5_statics_t) +#define Curve_data astGLOBAL(Plot,Curve_data_t) +#define getattrib_buff astGLOBAL(Plot,GetAttrib_Buff) +#define splitvalue_buff astGLOBAL(Plot,SplitValue_Buff) +#define stripescapes_buff astGLOBAL(Plot,StripEscapes_Buff) +#define Grf_chv astGLOBAL(Plot,Grf_chv_t) +#define Grf_chh astGLOBAL(Plot,Grf_chh_t) +#define Grf_alpha astGLOBAL(Plot,Grf_alpha_t) +#define Grf_beta astGLOBAL(Plot,Grf_beta_t) + +static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; +#define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 ); +#define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 ); + +/* If thread safety is not needed, declare and initialise globals at static + variables. */ +#else + +/* Variables used within astGrfAttrs_ */ +static double grfattrs_attrs[ GRF__NATTR ]; /* Saved attribute values */ +static int grfattrs_nesting = 0; /* Nesting level. */ + +/* Variables used to pass information to the curve drawing functions. See + the prologues of functions Crv and CrvLine for details. */ +static double Crv_limit; +static double Crv_scerr; +static double Crv_tol; +static double Crv_ux0; +static double Crv_uy0; +static double Crv_vxl; +static double Crv_vyl; +static double Crv_xhi; +static double Crv_xl; +static double Crv_xlo; +static double Crv_yhi; +static double Crv_yl; +static double Crv_ylo; +static float *Crv_vxbrk; +static float *Crv_vybrk; +static float *Crv_xbrk; +static float *Crv_ybrk; +static float Crv_len; +static int Crv_ink; +static int Crv_nbrk; +static int Crv_nent = 0; +static int Crv_out; +static int Crv_clip; +static void (*Crv_map)( int, double *, double *, double *, const char *, const char *, int * ); + +/* A cache of information calculated by the grf module. */ +static double Grf_chv = AST__BAD; +static double Grf_chh = AST__BAD; +static float Grf_alpha = 0.0; +static float Grf_beta = 0.0; + +/* The lower and upper bounds of the graphics coordinates enclosing all + lines and numerical labels drawn by astGrid. */ +static float Box_lbnd[ 2 ] = {FLT_MAX, FLT_MAX }; +static float Box_ubnd[ 2 ] = {FLT_MIN, FLT_MIN }; + +/* The lower and upper bounds of the graphics coordinates enclosing all + drawn graphics primatives, maintained by functions GLine, GMark and + DrawText. */ +static float Boxp_lbnd[ 2 ] = {FLT_MAX, FLT_MAX }; +static float Boxp_ubnd[ 2 ] = {FLT_MIN, FLT_MIN }; +static int Boxp_freeze = 0; + +/* Variables used to stored buffered poly lines (see functions Opoly, Bpoly + and Apoly). */ +static float *Poly_x = NULL; +static float *Poly_y = NULL; +static int Poly_n = 0; +static float **Poly_xp = NULL; +static float **Poly_yp = NULL; +static int *Poly_np = NULL; +static int Poly_npoly = 0; + +/* Variables used by function Map1. See the prologue of Map1 for details. */ +static int Map1_ncoord; +static AstPlot *Map1_plot = NULL; +static AstMapping *Map1_map = NULL; +static AstFrame *Map1_frame = NULL; +static const double *Map1_origin = NULL; +static double Map1_length; +static void *Map1_statics = NULL; +static int Map1_axis; +static int Map1_norm; +static int Map1_log; + +/* Variables used by function Map2. See the prologue of Map2 for details. */ +static int Map2_ncoord; +static AstPlot *Map2_plot = NULL; +static AstMapping *Map2_map = NULL; +static double Map2_x0; +static double Map2_y0; +static double Map2_deltax; +static double Map2_deltay; +static void *Map2_statics = NULL; + +/* Variables used by function Map3. See the prologue of Map3 for details. */ +static int Map3_ncoord; +static AstPlot *Map3_plot = NULL; +static AstMapping *Map3_map = NULL; +static AstFrame *Map3_frame = NULL; +static const double *Map3_origin = NULL; +static const double *Map3_end = NULL; +static double Map3_scale; +static void *Map3_statics = NULL; + +/* Variables used by function Map4. See the prologue of Map4 for details. */ +static int Map4_ncoord; +static AstPlot *Map4_plot = NULL; +static AstMapping *Map4_map = NULL; +static AstMapping *Map4_umap = NULL; +static void *Map4_statics = NULL; + +/* Variables used by function Map5. See the prologue of Map5 for details. */ +static AstPlot *Map5_plot = NULL; +static AstMapping *Map5_map = NULL; +static AstRegion *Map5_region = NULL; +static void *Map5_statics = NULL; +static int Map5_ncoord; + +/* A structure which stores information about the breaks in the last curve + drawn using the public methods "astGridLine" and "astCurve". */ +static AstPlotCurveData Curve_data; + +/* Buffers for strings returned by various functions. */ +static char splitvalue_buff[ 200 ]; +static char stripescapes_buff[ AST__PLOT_STRIPESCAPES_BUFF_LEN + 1 ]; +static char getattrib_buff[ 200 ]; + + +/* Define the class virtual function table and its initialisation flag + as static variables. */ +static AstPlotVtab class_vtab; /* Virtual function table */ +static int class_init = 0; /* Virtual function table initialised? */ + +#define LOCK_MUTEX2 +#define UNLOCK_MUTEX2 + +#endif + +/* Macro to reset the cache of values caclulated by the grf module. */ +#define RESET_GRF \ + Grf_chh = AST__BAD; \ + Grf_chv = AST__BAD; \ + Grf_alpha = 0.0; \ + Grf_beta = 0.0; + + +/* Prototypes for Private Member Functions. */ +/* ======================================== */ + +static double GetTol( AstPlot *, int * ); +static int TestTol( AstPlot *, int * ); +static void ClearTol( AstPlot *, int * ); +static void SetTol( AstPlot *, double, int * ); + +static int GetGrid( AstPlot *, int * ); +static int TestGrid( AstPlot *, int * ); +static void ClearGrid( AstPlot *, int * ); +static void SetGrid( AstPlot *, int, int * ); + +static int GetTickAll( AstPlot *, int * ); +static int TestTickAll( AstPlot *, int * ); +static void ClearTickAll( AstPlot *, int * ); +static void SetTickAll( AstPlot *, int, int * ); + +static int GetForceExterior( AstPlot *, int * ); +static int TestForceExterior( AstPlot *, int * ); +static void ClearForceExterior( AstPlot *, int * ); +static void SetForceExterior( AstPlot *, int, int * ); + +static int GetBorder( AstPlot *, int * ); +static int TestBorder( AstPlot *, int * ); +static void ClearBorder( AstPlot *, int * ); +static void SetBorder( AstPlot *, int, int * ); + +static int GetInvisible( AstPlot *, int * ); +static int TestInvisible( AstPlot *, int * ); +static void ClearInvisible( AstPlot *, int * ); +static void SetInvisible( AstPlot *, int, int * ); + +static int GetInk( AstPlot *, int * ); +static int TestInk( AstPlot *, int * ); +static void ClearInk( AstPlot *, int * ); +static void SetInk( AstPlot *, int, int * ); + +static int GetClipOp( AstPlot *, int * ); +static int TestClipOp( AstPlot *, int * ); +static void ClearClipOp( AstPlot *, int * ); +static void SetClipOp( AstPlot *, int, int * ); + +static int GetClip( AstPlot *, int * ); +static int TestClip( AstPlot *, int * ); +static void ClearClip( AstPlot *, int * ); +static void SetClip( AstPlot *, int, int * ); + +static int GetGrf( AstPlot *, int * ); +static int TestGrf( AstPlot *, int * ); +static void ClearGrf( AstPlot *, int * ); +static void SetGrf( AstPlot *, int, int * ); + +static int GetDrawTitle( AstPlot *, int * ); +static int TestDrawTitle( AstPlot *, int * ); +static void ClearDrawTitle( AstPlot *, int * ); +static void SetDrawTitle( AstPlot *, int, int * ); + +static int GetDrawAxes( AstPlot *, int, int * ); +static int TestDrawAxes( AstPlot *, int, int * ); +static void ClearDrawAxes( AstPlot *, int, int * ); +static void SetDrawAxes( AstPlot *, int, int, int * ); + +static int GetAbbrev( AstPlot *, int, int * ); +static int TestAbbrev( AstPlot *, int, int * ); +static void ClearAbbrev( AstPlot *, int, int * ); +static void SetAbbrev( AstPlot *, int, int, int * ); + +static int GetEscape( AstPlot *, int * ); +static int TestEscape( AstPlot *, int * ); +static void ClearEscape( AstPlot *, int * ); +static void SetEscape( AstPlot *, int, int * ); + +static double GetLabelAt( AstPlot *, int, int * ); +static int TestLabelAt( AstPlot *, int, int * ); +static void ClearLabelAt( AstPlot *, int, int * ); +static void SetLabelAt( AstPlot *, int, double, int * ); + +static double GetNumLabGap( AstPlot *, int, int * ); +static int TestNumLabGap( AstPlot *, int, int * ); +static void ClearNumLabGap( AstPlot *, int, int * ); +static void SetNumLabGap( AstPlot *, int, double, int * ); + +static double GetTextLabGap( AstPlot *, int, int * ); +static int TestTextLabGap( AstPlot *, int, int * ); +static void ClearTextLabGap( AstPlot *, int, int * ); +static void SetTextLabGap( AstPlot *, int, double, int * ); + +static double GetCentre( AstPlot *, int, int * ); +static int TestCentre( AstPlot *, int, int * ); +static void ClearCentre( AstPlot *, int, int * ); +static void SetCentre( AstPlot *, int, double, int * ); + +static double GetGap( AstPlot *, int, int * ); +static int TestGap( AstPlot *, int, int * ); +static void ClearGap( AstPlot *, int, int * ); +static void SetGap( AstPlot *, int, double, int * ); + +static int GetLabelling( AstPlot *, int * ); +static int TestLabelling( AstPlot *, int * ); +static void ClearLabelling( AstPlot *, int * ); +static void SetLabelling( AstPlot *, int, int * ); + +static double GetMajTickLen( AstPlot *, int, int * ); +static int TestMajTickLen( AstPlot *, int, int * ); +static void ClearMajTickLen( AstPlot *, int, int * ); +static void SetMajTickLen( AstPlot *, int, double, int * ); + +static double GetLogGap( AstPlot *, int, int * ); +static int TestLogGap( AstPlot *, int, int * ); +static void ClearLogGap( AstPlot *, int, int * ); +static void SetLogGap( AstPlot *, int, double, int * ); + +static double GetTitleGap( AstPlot *, int * ); +static int TestTitleGap( AstPlot *, int * ); +static void ClearTitleGap( AstPlot *, int * ); +static void SetTitleGap( AstPlot *, double, int * ); + +static double GetMinTickLen( AstPlot *, int, int * ); +static int TestMinTickLen( AstPlot *, int, int * ); +static void ClearMinTickLen( AstPlot *, int, int * ); +static void SetMinTickLen( AstPlot *, int, double, int * ); + +static int GetEdge( AstPlot *, int, int * ); +static int TestEdge( AstPlot *, int, int * ); +static void ClearEdge( AstPlot *, int, int * ); +static void SetEdge( AstPlot *, int, int, int * ); + +static int GetLabelUp( AstPlot *, int, int * ); +static int TestLabelUp( AstPlot *, int, int * ); +static void ClearLabelUp( AstPlot *, int, int * ); +static void SetLabelUp( AstPlot *, int, int, int * ); + +static int GetLogPlot( AstPlot *, int, int * ); +static int TestLogPlot( AstPlot *, int, int * ); +static void ClearLogPlot( AstPlot *, int, int * ); +static void SetLogPlot( AstPlot *, int, int, int * ); + +static int GetLogTicks( AstPlot *, int, int * ); +static int TestLogTicks( AstPlot *, int, int * ); +static void ClearLogTicks( AstPlot *, int, int * ); +static void SetLogTicks( AstPlot *, int, int, int * ); + +static int GetLogLabel( AstPlot *, int, int * ); +static int TestLogLabel( AstPlot *, int, int * ); +static void ClearLogLabel( AstPlot *, int, int * ); +static void SetLogLabel( AstPlot *, int, int, int * ); + +static int GetNumLab( AstPlot *, int, int * ); +static int TestNumLab( AstPlot *, int, int * ); +static void ClearNumLab( AstPlot *, int, int * ); +static void SetNumLab( AstPlot *, int, int, int * ); + +static int GetMinTick( AstPlot *, int, int * ); +static int TestMinTick( AstPlot *, int, int * ); +static void ClearMinTick( AstPlot *, int, int * ); +static void SetMinTick( AstPlot *, int, int, int * ); + +static int GetTextLab( AstPlot *, int, int * ); +static int TestTextLab( AstPlot *, int, int * ); +static void ClearTextLab( AstPlot *, int, int * ); +static void SetTextLab( AstPlot *, int, int, int * ); + +static int GetLabelUnits( AstPlot *, int, int * ); +static int TestLabelUnits( AstPlot *, int, int * ); +static void ClearLabelUnits( AstPlot *, int, int * ); +static void SetLabelUnits( AstPlot *, int, int, int * ); + +static int GetStyle( AstPlot *, int, int * ); +static int TestStyle( AstPlot *, int, int * ); +static void ClearStyle( AstPlot *, int, int * ); +static void SetStyle( AstPlot *, int, int, int * ); + +static int GetFont( AstPlot *, int, int * ); +static int TestFont( AstPlot *, int, int * ); +static void ClearFont( AstPlot *, int, int * ); +static void SetFont( AstPlot *, int, int, int * ); + +static int GetColour( AstPlot *, int, int * ); +static int TestColour( AstPlot *, int, int * ); +static void ClearColour( AstPlot *, int, int * ); +static void SetColour( AstPlot *, int, int, int * ); + +static double GetWidth( AstPlot *, int, int * ); +static int TestWidth( AstPlot *, int, int * ); +static void ClearWidth( AstPlot *, int, int * ); +static void SetWidth( AstPlot *, int, double, int * ); + +static double GetSize( AstPlot *, int, int * ); +static int TestSize( AstPlot *, int, int * ); +static void ClearSize( AstPlot *, int, int * ); +static void SetSize( AstPlot *, int, double, int * ); + +static const char *GetAttrib( AstObject *, const char *, int * ); +static int TestAttrib( AstObject *, const char *, int * ); +static void ClearAttrib( AstObject *, const char *, int * ); +static void SetAttrib( AstObject *, const char *, int * ); + +static AstFrameSet *Fset2D( AstFrameSet *, int, int * ); +static AstKeyMap *GetGrfContext( AstPlot *, int * ); +static AstPlotCurveData **CleanCdata( AstPlotCurveData **, int * ); +static AstPlotCurveData **DrawGrid( AstPlot *, TickInfo **, int, const char *, const char *, int * ); +static AstPointSet *DefGap( AstPlot *, double *, int *, double *, int *, const char *, const char *, int * ); +static AstPointSet *GetDrawnTicks( AstPlot *, int, int, int * ); +static AstPointSet *Trans( AstPlot *, AstFrame *, AstMapping *, AstPointSet *, int, AstPointSet *, int, const char *, const char *, int * ); +static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); +static TickInfo **CleanGrid( TickInfo **, int * ); +static TickInfo **GridLines( AstPlot *, double *, double *, int *, const char *, const char *, int * ); +static TickInfo *TickMarks( AstPlot *, int, double *, double *, int *, GetTicksStatics **, const char *, const char *, int * ); +static char **CheckLabels2( AstPlot *, AstFrame *, int, double *, int, char **, double, int * ); +static char *FindWord( char *, const char *, const char **, int * ); +static char *GrfItem( int, const char *, int *, int * ); +static const char *JustMB( AstPlot *, int, const char *, float *, float *, float, float, const char *, float, float, float, float, float *, float *, const char *, const char *, int * ); +static const char *SplitValue( AstPlot *, const char *, int, int *, int * ); +static double **MakeGrid( AstPlot *, AstFrame *, AstMapping *, int, int, double, double, double, double, int, AstPointSet **, AstPointSet**, int, const char *, const char *, int * ); +static double GetTicks( AstPlot *, int, double *, double **, int *, double **, int *, int, int *, double *, GetTicksStatics **, const char *, const char *, int * ); +static double GetUseSize( AstPlot *, int, int * ); +static double GetUseWidth( AstPlot *, int, int * ); +static double GoodGrid( AstPlot *, int *, AstPointSet **, AstPointSet **, const char *, const char *, int * ); +static double Typical( int, double *, double, double, double *, int * ); +static int Border( AstPlot *, int * ); +static int Boundary( AstPlot *, const char *, const char *, int * ); +static int BoxCheck( float *, float *, float *, float *, int * ); +static int CGAttrWrapper( AstPlot *, int, double, double *, int, int * ); +static int CGBBufWrapper( AstPlot *, int * ); +static int CGCapWrapper( AstPlot *, int, int, int * ); +static int CGEBufWrapper( AstPlot *, int * ); +static int CGFlushWrapper( AstPlot *, int * ); +static int CGLineWrapper( AstPlot *, int, const float *, const float *, int * ); +static int CGMarkWrapper( AstPlot *, int, const float *, const float *, int, int * ); +static int CGQchWrapper( AstPlot *, float *, float *, int * ); +static int CGScalesWrapper( AstPlot *, float *, float *, int * ); +static int CGTextWrapper( AstPlot *, const char *, float, float, const char *, float, float, int * ); +static int CGTxExtWrapper( AstPlot *, const char *, float, float, const char *, float, float, float *, float *, int * ); +static int CheckLabels( AstPlot *, AstFrame *, int, double *, int, int, char **, double, int * ); +static int ChrLen( const char *, int * ); +static int Compare_LL( const void *, const void * ); +static int Compared( const void *, const void * ); +static int CountGood( int, double *, int * ); +static int Cross( float, float, float, float, float, float, float, float, int * ); +static int CvBrk( AstPlot *, int, double *, double *, double *, int * ); +static int DrawRegion( AstPlot *, AstFrame *, const char *, const char *, int * ); +static int EdgeCrossings( AstPlot *, int, int, double, double *, double **, EdgeCrossingsStatics **, const char *, const char *, int * ); +static int EdgeLabels( AstPlot *, int, TickInfo **, AstPlotCurveData **, int, const char *, const char *, int * ); +static int FindDPTZ( AstFrame *, int, const char *, const char *, int *, int *, int * ); +static int FindMajTicks( AstMapping *, AstFrame *, int, double, double, double , double *, int, double *, double **, int * ); +static int FindMajTicks2( int, double, double, int, double *, double **, int * ); +static int FindString( int, const char *[], const char *, const char *, const char *, const char *, int * ); +static int Fpoly_ecmp( const void *, const void * ); +static int Fpoly_scmp( const void *, const void * ); +static int FullForm( const char *, const char *, const char *, const char *, const char *, int * ); +static int GCap( AstPlot *, int, int, int * ); +static int GVec( AstPlot *, AstMapping *, double *, int, double, AstPointSet **, AstPointSet **, double *, double *, double *, double *, int *, const char *, const char *, int * ); +static int GetUseColour( AstPlot *, int, int * ); +static int GetUseFont( AstPlot *, int, int * ); +static int GetUseStyle( AstPlot *, int, int * ); +static int GraphGrid( int, int, double, double, double, double, double **, int * ); +static int HasEscapes( const char *, int * ); +static int IdFind( int, int, int *, int *, int *, int * ); +static int Inside( int, float *, float *, float, float, int * ); +static int IsASkyAxis( AstFrame *, int, int * ); +static int IsASkyFrame( AstObject *, int * ); +static int Labelat( AstPlot *, TickInfo **, AstPlotCurveData **, double *, const char *, const char *, int * ); +static int Overlap( AstPlot *, int, int, const char *, float, float, const char *, float, float, float **, const char *, const char *, int * ); +static int PopGat( AstPlot *, float *, const char *, const char *, int * ); +static int TestUseColour( AstPlot *, int, int * ); +static int TestUseFont( AstPlot *, int, int * ); +static int TestUseSize( AstPlot *, int, int * ); +static int TestUseStyle( AstPlot *, int, int * ); +static int TestUseWidth( AstPlot *, int, int * ); +static int ToggleLogLin( AstPlot *, int, int, const char *, int * ); +static int TraceBorder( AstPlot *, AstMapping *, double, double, double, double, int, double, int[ 4 ], const char *, const char *, int * ); +static int Ustrcmp( const char *, const char *, int * ); +static int Ustrncmp( const char *, const char *, size_t, int * ); +static int swapEdges( AstPlot *, TickInfo **, AstPlotCurveData **, int * ); +static void AddCdt( AstPlotCurveData *, AstPlotCurveData *, const char *, const char *, int * ); +static void Apoly( AstPlot *, float, float, int * ); +static void AxPlot( AstPlot *, int, const double *, double, int, AstPlotCurveData *, const char *, const char *, int * ); +static void BBuf( AstPlot *, int * ); +static void BoundingBox( AstPlot *, float[2], float[2], int * ); +static void Bpoly( AstPlot *, float, float, int * ); +static void Clip( AstPlot *, int, const double [], const double [], int * ); +static void Copy( const AstObject *, AstObject *, int * ); +static void CopyPlotDefaults( AstPlot *, int, AstPlot *, int, int * ); +static void Crv( AstPlot *this, double *, double *, double *, int, double *, CrvStatics *, const char *, const char *, int * ); +static void CrvLine( AstPlot *this, double, double, double, double, const char *, const char *, int * ); +static void Curve( AstPlot *, const double [], const double [], int * ); +static void CurvePlot( AstPlot *, const double *, const double *, int , AstPlotCurveData *, const char *, const char *, int * ); +static void Delete( AstObject *, int * ); +static void DrawAxis( AstPlot *, TickInfo **, double *, double *, const char *, const char *, int * ); +static void DrawText( AstPlot *, int, int, const char *, float, float, const char *, float, float, float *, float *, float *, const char *, const char *, int * ); +static void DrawTicks( AstPlot *, TickInfo **, int, double *, double *, const char *, const char *, int * ); +static void Dump( AstObject *, AstChannel *, int * ); +static void EBuf( AstPlot *, int * ); +static void Fpoly( AstPlot *, const char *, const char *, int * ); +static void GAttr( AstPlot *, int, double, double *, int, const char *, const char *, int * ); +static void GBBuf( AstPlot *, const char *, const char *, int * )__attribute__((unused)); +static void GEBuf( AstPlot *, const char *, const char *, int * )__attribute__((unused)); +static void GFlush( AstPlot *, const char *, const char *, int * )__attribute__((unused)); +static void GLine( AstPlot *, int, const float *, const float *, const char *, const char *, int * ); +static void GMark( AstPlot *, int, const float *, const float *, int, const char *, const char *, int * ); +static void GQch( AstPlot *, float *, float *, const char *, const char *, int * ); +static void GScales( AstPlot *, float *, float *, const char *, const char *, int * ); +static void GText( AstPlot *, const char *, float, float, const char *, float, float, const char *, const char *, int * ); +static void GTxExt( AstPlot *, const char *, float , float, const char *, float, float, float *, float *, const char *, const char *, int * ); +static void GenCurve( AstPlot *, AstMapping *, int * ); +static void GrfPop( AstPlot *, int * ); +static void GrfPush( AstPlot *, int * ); +static void GrfSet( AstPlot *, const char *, AstGrfFun, int * ); +static void GrfWrapper( AstPlot *, const char *, AstGrfWrap, int * ); +static void Grid( AstPlot *, int * ); +static void GridLine( AstPlot *, int, const double [], double, int * ); +static void InterpEscape( AstPlot *, int, double, float *, float *, float, float, float, float, const char *, float *, double, double, double, double, double, const char *, const char *, int * ); +static void Labels( AstPlot *, TickInfo **, AstPlotCurveData **, double *, double *, const char *, const char *, int * ); +static void LinePlot( AstPlot *, double, double, double, double, int, AstPlotCurveData *, const char *, const char *, int * ); +static void Map1( int, double *, double *, double *, const char *, const char *, int * GLOBALS_PROTO ); +static void Map2( int, double *, double *, double *, const char *, const char *, int * GLOBALS_PROTO ); +static void Map3( int, double *, double *, double *, const char *, const char *, int * GLOBALS_PROTO ); +static void Map4( int, double *, double *, double *, const char *, const char *, int * GLOBALS_PROTO ); +static void Map5( int, double *, double *, double *, const char *, const char *, int * GLOBALS_PROTO ); +static void Mark( AstPlot *, int, int, int, const double *, int, int * ); +static void Mirror( AstPlot *, int, int * ); +static void Norm1( AstMapping *, int, int, double *, double, double, int * ); +static void Opoly( AstPlot *, int * ); +static void PlotLabels( AstPlot *, int, AstFrame *, int, LabelList *, char *, int, float **, const char *, const char *, int * ); +static void PolyCurve( AstPlot *, int, int, int, const double *, int * ); +static void PurgeCdata( AstPlotCurveData *, int * ); +static void PushGat( AstPlot *, float, const char *, const char *, int * ); +static void RegionOutline( AstPlot *, AstRegion *, int * ); +static void RemoveFrame( AstFrameSet *, int, int * ); +static void RightVector( AstPlot *, float *, float *, float *, float *, const char *, const char *, int * ); +static void SaveTick( AstPlot *, int, double, double, int, int * ); +static void SetTickValues( AstPlot *, int, int, double *, int, double *, int * ); +static void Text( AstPlot *, const char *, const double [], const float [], const char *, int * ); +static void TextLabels( AstPlot *, int, int *, const char *, const char *, int * ); +static void Ticker( AstPlot *, int, int, double, double *, double, int, int, EdgeCrossingsStatics **, const char *, const char *, int * ); +static void UpdateConcat( float *, float *, float, float, float, float, float *, float *, float, float, float *, float *, float *, float *, int * ); + +#if defined(THREAD_SAFE) +static int ManageLock( AstObject *, int, int, AstObject **, int * ); +#endif + +/* Functions which access class attributes. */ +/* ======================================= */ +/* Implement member functions to access the attributes associated with this + class using the macros defined for this purpose in the "object.h" file. For + a description of each attribute, see the class interface (in the associated + .h file). */ + +/* Tol. */ +/* ---- */ +/* +*att++ +* Name: +* Tol + +* Purpose: +* Plotting tolerance. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute specifies the plotting tolerance (or resolution) +* to be used for the graphical output produced by a Plot. Smaller +* values will result in smoother and more accurate curves being +* drawn, but may slow down the plotting process. Conversely, +* larger values may speed up the plotting process in cases where +* high resolution is not required. +* +* The Tol value should be given as a fraction of the minimum +* dimension of the plotting area, and should lie in the range +c from 1.0e-7 to 1.0. By default, a value of 0.01 is used. +f from 1.0E-7 to 1.0. By default, a value of 0.01 is used. + +* Applicability: +* Plot +* All Plots have this attribute. +*att-- +*/ +/* The plotting tolerance. Has a value of -1.0 when not set yielding a +default value of 0.01. Usable values are in the range 1.0E-7 to 1.0. */ +astMAKE_CLEAR(Plot,Tol,tol,-1.0) +astMAKE_GET(Plot,Tol,double,0.01,(this->tol == -1.0 ? 0.01 : this->tol)) +astMAKE_SET(Plot,Tol,double,tol,astMIN(astMAX(value,1.0E-7),1.0)) +astMAKE_TEST(Plot,Tol,( this->tol != -1.0 )) + +/* Grid. */ +/* ----- */ +/* +*att++ +* Name: +* Grid + +* Purpose: +* Draw grid lines for a Plot? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* whether grid lines (a grid of curves marking the "major" values +* on each axis) are drawn across the plotting area. +* +* If the Grid value of a Plot is non-zero, then grid lines will be +* drawn. Otherwise, short tick marks on the axes are used to mark +* the major axis values. The default behaviour is to use tick +* marks if the entire plotting area is filled by valid physical +* coordinates, but to draw grid lines otherwise. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - The spacing between major axis values, which determines the +* spacing of grid lines, may be set using the Gap(axis) attribute. +*att-- +*/ +/* If non-zero use lines instead of tick marks in a coordinate grid. Has a +value of -1 when not set yielding a default value of 0. */ +astMAKE_CLEAR(Plot,Grid,grid,-1) +astMAKE_GET(Plot,Grid,int,0,(this->grid == -1 ? 0 : this->grid)) +astMAKE_SET(Plot,Grid,int,grid,( value ? 1 : 0 )) +astMAKE_TEST(Plot,Grid,( this->grid != -1 )) + +MAKE_GET2(Plot,Grid,int,0,this->ugrid) +MAKE_SET2(Plot,Grid,int,ugrid,( value ? 1 : 0 )) + +/* Invisible. */ +/* ---------- */ +/* +*att++ +* Name: +* Invisible + +* Purpose: +* Draw graphics using invisible ink? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of all graphics produced by +* Plot methods by determining whether graphics should be visible or +* invisible. +* +* If the Invisible value of a Plot is non-zero, then all the Plot +* methods which normally generate graphical output do not do so (you +* can think of them drawing with "invisible ink"). Such methods do, +* however, continue to do all the calculations which would be needed to +* produce the graphics. In particular, the bounding box enclosing the +* graphics is still calculated and can be retrieved as normal using +c astBoundingBox. The default value is zero, resulting in all methods +f AST_BOUNDINGBOX. The default value is zero, resulting in all methods +* drawing graphics as normal, using visible ink. + +* Applicability: +* Plot +* All Plots have this attribute. + +*att-- +*/ +/* If non-zero use invisible ink. Has a value of -1 when not set yielding +a default value of 0. */ +astMAKE_CLEAR(Plot,Invisible,invisible,-1) +astMAKE_GET(Plot,Invisible,int,0,(this->invisible == -1 ? 0 : this->invisible)) +astMAKE_SET(Plot,Invisible,int,invisible,( value ? 1 : 0 )) +astMAKE_TEST(Plot,Invisible,( this->invisible != -1 )) + +/* TickAll */ +/* ------- */ +/* +*att++ +* Name: +* TickAll + +* Purpose: +* Draw tick marks on all edges of a Plot? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* whether tick marks should be drawn on all edges of a Plot. +* +* If the TickAll value of a Plot is non-zero (the default), then +* tick marks will be drawn on all edges of the Plot. Otherwise, +* they will be drawn only on those edges where the numerical and +* descriptive axis labels are drawn (see the Edge(axis) +* attribute). + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - In some circumstances, numerical labels and tick marks are +* drawn along grid lines inside the plotting area, rather than +* around its edges (see the Labelling attribute). In this case, +* the value of the TickAll attribute is ignored. +*att-- +*/ +/* If non-zero put tick marks on opposite edges. Has a value of -1 when not +set yielding a default value of 1. */ +astMAKE_CLEAR(Plot,TickAll,tickall,-1) +astMAKE_GET(Plot,TickAll,int,1,(this->tickall == -1 ? 1 : this->tickall)) +astMAKE_SET(Plot,TickAll,int,tickall,( value ? 1 : 0 )) +astMAKE_TEST(Plot,TickAll,( this->tickall != -1 )) + +/* ForceExterior */ +/* ------------- */ +/* +*att+ +* Name: +* ForceExterior + +* Purpose: +* Force the use of exterior labelling? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by forcing +f coordinate grid (drawn with the AST_GRID routine) by forcing +* labels and tick marks to be drawn round the edges of the plot +* (rather than across the middle of the plot), even if there appear +* to be insufficient edge crossings to justify the use of exterior +* labelling. +* +* The default value of zero results in the decision about whether to +* use interior or exterior labelling being made purely on the basis +* of the value of the Labelling attribute. If ForceExterior is set to +* a non-zero value, then the Labelling attribute is ignored and exterior +* labelling will always be attempted, even if there appear to be +* insufficient edge labels to justify their use. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - The value of this attribute is currently under investigation, and +* so this attribute prologue is currently marked as protected rather +* than public (in order to prevent it being included in the public +* documentation). +*att- +*/ +astMAKE_CLEAR(Plot,ForceExterior,forceexterior,-1) +astMAKE_GET(Plot,ForceExterior,int,0,(this->forceexterior == -1 ? 0 : this->forceexterior)) +astMAKE_SET(Plot,ForceExterior,int,forceexterior,( value ? 1 : 0 )) +astMAKE_TEST(Plot,ForceExterior,( this->forceexterior != -1 )) + +/* +*att++ +* Name: +* Border + +* Purpose: +* Draw a border around valid regions of a Plot? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* whether a border is drawn around regions corresponding to the +c valid physical coordinates of a Plot (c.f. astBorder). +f valid physical coordinates of a Plot (c.f. AST_BORDER). +* +* If the Border value of a Plot is non-zero, then this border will +* be drawn as part of the grid. Otherwise, the border is not drawn +* (although axis labels and tick marks will still appear, unless +* other relevant Plot attributes indicate that they should +* not). The default behaviour is to draw the border if tick marks +* and numerical labels will be drawn around the edges of the +* plotting area (see the Labelling attribute), but to omit it +* otherwise. + +* Applicability: +* Plot +* All Plots have this attribute. +*att-- +*/ +/* If non-zero draw the border. Has a value of -1 when not set, yeilding + a default of 1. */ +astMAKE_CLEAR(Plot,Border,border,-1) +astMAKE_SET(Plot,Border,int,border,( value ? 1 : 0 )) +astMAKE_TEST(Plot,Border,( this->border != -1 )) +astMAKE_GET(Plot,Border,int,1,(this->border == -1 ? 1 : this->border)) + +MAKE_SET2(Plot,Border,int,uborder,( value ? 1 : 0 )) +MAKE_GET2(Plot,Border,int,1,this->uborder) + +/* Clip */ +/* ---- */ +/* +*att++ +* Name: +* Clip + +* Purpose: +* Clip lines and/or markers at the Plot boundary? + +* Type: +* Public attribute. + +* Synopsis: +* Integer. + +* Description: +* This attribute controls whether curves and markers are clipped at the +* boundary of the graphics box specified when the Plot was created. A +* value of 3 implies both markers and curves are clipped at the Plot +* boundary. A value of 2 implies markers are clipped, but not curves. A +* value of 1 implies curves are clipped, but not markers. A value of +* zero implies neither curves nor markers are clipped. The default +* value is 1. Note, this attributes controls only the clipping +* performed internally within AST. The underlying graphics system may +* also apply clipping. In such cases, removing clipping using this +* attribute does not guarantee that no clipping will be visible in the +* final plot. +* +c The astClip function +f The AST_CLIP routine +* can be used to establish generalised clipping within arbitrary +* regions of the Plot. + +* Applicability: +* Plot +* All Plots have this attribute. +*att-- +*/ +astMAKE_CLEAR(Plot,Clip,clip,-1) +astMAKE_GET(Plot,Clip,int,0,(this->clip == -1 ? 1 : this->clip)) +astMAKE_TEST(Plot,Clip,( this->clip != -1 )) +astMAKE_SET(Plot,Clip,int,clip,((value>=0&&value<=3)?value:(astError( AST__ATTIN, "astSetClip(Plot): Invalid value %d supplied for Clip attribute", status, value ), this->clip))) + +/* ClipOp */ +/* ------ */ +/* +*att++ +* Name: +* ClipOp + +* Purpose: +* Combine Plot clipping limits using a boolean OR? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls how the clipping limits specified for +c each axis of a Plot (using the astClip function) are +f each axis of a Plot (using the AST_CLIP routine) are +* combined. This, in turn, determines which parts of the graphical +* output will be visible. +* +* If the ClipOp attribute of a Plot is zero (the default), +* graphical output is visible only if it satisfies the clipping +* limits on all the axes of the clipping Frame (a boolean +* AND). Otherwise, if ClipOp is non-zero, output is visible if it +* satisfies the clipping limits on one or more axes (a boolean +* OR). +* +* An important use of this attribute is to allow areas of a Plot +* to be left clear (e.g. as a background for some text). To +* achieve this, the lower and upper clipping bounds supplied to +c astClip should be reversed, and the ClipOp attribute of the +f AST_CLIP should be reversed, and the ClipOp attribute of the +* Plot should be set to a non-zero value. + +* Applicability: +* Plot +* All Plots have this attribute. +*att-- +*/ +/* If non-zero only 1axis need be within the clipping bounds to avoid a +point being clipped. Otherwise, all axes must be within bounds. */ +astMAKE_CLEAR(Plot,ClipOp,clipop,-1) +astMAKE_GET(Plot,ClipOp,int,0,(this->clipop == -1 ? 0 : this->clipop)) +astMAKE_SET(Plot,ClipOp,int,clipop,( value ? 1 : 0 )) +astMAKE_TEST(Plot,ClipOp,( this->clipop != -1 )) + +/* Grf. */ +/* ---- */ +/* +*att++ +* Name: +* Grf + +* Purpose: +c Use Grf functions registered through astGrfSet? +f Use Grf routines registered through AST_GRFSET? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +c This attribute selects the functions which are used to draw graphics by +c the Plot class. If it is zero, then the functions in the graphics +c interface selected at link-time are used (see the ast_link script). +c Otherwise, functions registered using astGrfSet are used. In this +c case, if a function is needed which has not been registered, +c then the function in the graphics interface selected at link-time is +c used. +f This attribute selects the routines which are used to draw graphics by +f the Plot class. If it is zero, then the routines in the graphics +f interface selected at link-time are used (see the ast_link script). +f Otherwise, routines registered using AST_GRFSET are used. In this +f case, if a routine is needed which has not been registered, +f then the routine in the graphics interface selected at link-time is +f used. + +* The default is to use the graphics interface + +* Applicability: +* Plot +* All Plots have this attribute. +* Plot3D +* The Plot3D class ignores this attributes, assuming a value of +* zero. + +* Notes: +* - The value of this attribute is not saved when the Plot is written +* out through a Channel to an external data store. On re-loading such +c a Plot using astRead, the attribute will be cleared, resulting in the +f a Plot using AST_READ, the attribute will be cleared, resulting in the +* graphics interface selected at link-time being used. + +*att-- +*/ +/* Use Grf routines registered using astGrfSet? Has a +value of -1 when not set yielding a default of 0. */ +astMAKE_CLEAR(Plot,Grf,grf,-1) +astMAKE_GET(Plot,Grf,int,0,(this->grf == -1 ? 0 : this->grf)) +astMAKE_SET(Plot,Grf,int,grf,( value ? 1 : 0 )) +astMAKE_TEST(Plot,Grf,( this->grf != -1 )) + +/* DrawTitle */ +/* --------- */ +/* +*att++ +* Name: +* DrawTitle + +* Purpose: +* Draw a title for a Plot? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* whether a title is drawn. +* +* If the DrawTitle value of a Plot is non-zero (the default), then +* the title will be drawn, otherwise it will be omitted. + +* Applicability: +* Plot +* All Plots have this attribute. +* Plot3D +* The Plot3D class ignores this attributes, assuming a value of +* zero. + +* Notes: +* - The text used for the title is obtained from the Plot's Title +* attribute. +* - The vertical placement of the title can be controlled using +* the TitleGap attribute. +*att-- +*/ +/* If non-zero add a title to the grid. Has a value of -1 when not +set yielding a default value of 1. */ +astMAKE_CLEAR(Plot,DrawTitle,drawtitle,-1) +astMAKE_GET(Plot,DrawTitle,int,1,(this->drawtitle == -1 ? 1 : this->drawtitle)) +astMAKE_SET(Plot,DrawTitle,int,drawtitle,( value ? 1 : 0 )) +astMAKE_TEST(Plot,DrawTitle,( this->drawtitle != -1 )) + +/* LabelUp. */ +/* ------- */ +/* +*att++ +* Name: +* LabelUp(axis) + +* Purpose: +* Draw numerical Plot labels upright? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* whether the numerical labels for each axis of a Plot should be +* drawn upright or not. It takes a separate value for each +* physical axis of a Plot so that, for instance, the setting +* "LabelUp(2)=1" specifies that numerical labels for the second +* axis should be drawn upright. +* +* If the LabelUp value of a Plot axis is non-zero, it causes +* numerical labels for that axis to be plotted upright (i.e. as +* normal, horizontal text), otherwise labels are drawn parallel to +* the axis to which they apply. +* +* The default is to produce upright labels if the labels are placed +* around the edge of the plot, and to produce labels that follow the +* axes if the labels are placed within the interior of the plot (see +* attribute Labelling). + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - In some circumstances, numerical labels and tick marks are +* drawn around the edges of the plotting area (see the Labelling +* attribute). In this case, the value of the LabelUp attribute is +* ignored. +* - If no axis is specified, (e.g. "LabelUp" instead of +* "LabelUp(2)"), then a "set" or "clear" operation will affect the +* attribute value of all the Plot axes, while a "get" or "test" +* operation will use just the LabelUp(1) value. +*att-- +*/ +/* Are numerical labels to be displayed on each axis? Has a value of -1 when +not set yielding a value of 0 (no) for both axes. */ +MAKE_CLEAR(LabelUp,labelup,-1,0) +MAKE_GET(LabelUp,int,0,( this->labelup[axis] == -1 ? 0 : this->labelup[axis] ),0) +MAKE_TEST(LabelUp,( this->labelup[axis] != -1 ),0) +MAKE_SET(LabelUp,int,labelup,( value ? 1 : 0 ),0) + +/* DrawAxes */ +/* -------- */ +/* +*att++ +* Name: +* DrawAxes(axis) + +* Purpose: +* Draw axes for a Plot? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* whether curves representing coordinate axes should be drawn. +* It takes a separate value for each physical axis of a +* Plot so that, for instance, the setting "DrawAxes(2)=0" +* specifies that no axis should be drawn for the second axis. +* +* If drawn, these axis lines will pass through any tick marks +* associated with numerical labels drawn to mark values on the +* axes. The location of these tick marks and labels (and hence the +* axis lines) is determined by the Plot's LabelAt(axis) attribute. +* +* If the DrawAxes value of a Plot is non-zero (the default), then +* axis lines will be drawn, otherwise they will be omitted. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - Axis lines are drawn independently of any coordinate grid +* lines (see the Grid attribute) so grid lines may be used to +* substitute for axis lines if required. +* - In some circumstances, numerical labels and tick marks are +* drawn around the edges of the plotting area (see the Labelling +* attribute). In this case, the value of the DrawAxes attribute +* is ignored. +* - If no axis is specified, (e.g. "DrawAxes" instead of +* "DrawAxes(2)"), then a "set" or "clear" operation will affect +* the attribute value of all the Plot axes, while a "get" or +* "test" operation will use just the DrawAxes(1) value. +*att-- +*/ +/* If non-zero draw a curve through the tick marks. Has a value of -1 + when not set yielding a default value of 1. */ +MAKE_CLEAR(DrawAxes,drawaxes,-1,0) +MAKE_GET(DrawAxes,int,1,( this->drawaxes[axis] == -1 ? 1 : this->drawaxes[axis] ),0) +MAKE_TEST(DrawAxes,( this->drawaxes[axis] != -1 ),0) +MAKE_SET(DrawAxes,int,drawaxes,( value ? 1 : 0 ),0) + +/* Abbrev */ +/* -------- */ +/* +*att++ +* Name: +* Abbrev(axis) + +* Purpose: +* Abbreviate leading fields within numerical axis labels? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* whether matching leading fields should be removed from adjacent +* numerical axis labels. It takes a separate value for each physical +* axis of a Plot so that, for instance, the setting "Abbrev(2)=0" +* specifies that matching leading fields should not be removed on +* the second axis. +* +* If the Abbrev value of a Plot is non-zero (the default), then +* leading fields will be removed from adjacent axis labels if they +* are equal. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - If no axis is specified, (e.g. "Abbrev" instead of +* "Abbrev(2)"), then a "set" or "clear" operation will affect +* the attribute value of all the Plot axes, while a "get" or +* "test" operation will use just the Abbrev(1) value. +*att-- +*/ +MAKE_CLEAR(Abbrev,abbrev,-1,0) +MAKE_GET(Abbrev,int,1,( this->abbrev[axis] == -1 ? 1 : this->abbrev[axis] ),0) +MAKE_TEST(Abbrev,( this->abbrev[axis] != -1 ),0) +MAKE_SET(Abbrev,int,abbrev,( value ? 1 : 0 ),0) + +/* Escape. */ +/* ------- */ +/* +*att++ +* Name: +* Escape + +* Purpose: +* Allow changes of character attributes within strings? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of text strings and numerical +c labels drawn by the astGrid and (for the Plot class) astText functions, +f labels drawn by the AST_GRID and (for the Plot class) AST_TEXT routines, +* by determining if any escape sequences contained within the strings +* should be used to control the appearance of the text, or should +* be printed literally. Note, the Plot3D class only interprets escape +* sequences within the +c astGrid function. +f AST_GRID routine. +* +* If the Escape value of a Plot is one (the default), then any +* escape sequences in text strings produce the effects described +* below when printed. Otherwise, they are printed literally. +* +c See also the astEscapes function. +f See also the AST_ESCAPES function. + +* Escape Sequences: +* Escape sequences are introduced into the text string by a percent +* "%" character. Any unrecognised, illegal or incomplete escape sequences +* are printed literally. The following escape sequences are +* currently recognised ("..." represents a string of one or more +* decimal digits): +* +* %% - Print a literal "%" character. +* +* %^...+ - Draw subsequent characters as super-scripts. The digits +* "..." give the distance from the base-line of "normal" +* text to the base-line of the super-script text, scaled +* so that a value of "100" corresponds to the height of +* "normal" text. +* %^+ - Draw subsequent characters with the normal base-line. +* +* %v...+ - Draw subsequent characters as sub-scripts. The digits +* "..." give the distance from the base-line of "normal" +* text to the base-line of the sub-script text, scaled +* so that a value of "100" corresponds to the height of +* "normal" text. +* +* %v+ - Draw subsequent characters with the normal base-line +* (equivalent to %^+). +* +* %>...+ - Leave a gap before drawing subsequent characters. +* The digits "..." give the size of the gap, scaled +* so that a value of "100" corresponds to the height of +* "normal" text. +* +* %<...+ - Move backwards before drawing subsequent characters. +* The digits "..." give the size of the movement, scaled +* so that a value of "100" corresponds to the height of +* "normal" text. +* +* %s...+ - Change the Size attribute for subsequent characters. The +* digits "..." give the new Size as a fraction of the +* "normal" Size, scaled so that a value of "100" corresponds +* to 1.0; +* +* %s+ - Reset the Size attribute to its "normal" value. +* +* %w...+ - Change the Width attribute for subsequent characters. The +* digits "..." give the new width as a fraction of the +* "normal" Width, scaled so that a value of "100" corresponds +* to 1.0; +* +* %w+ - Reset the Size attribute to its "normal" value. +* +* %f...+ - Change the Font attribute for subsequent characters. The +* digits "..." give the new Font value. +* +* %f+ - Reset the Font attribute to its "normal" value. +* +* %c...+ - Change the Colour attribute for subsequent characters. The +* digits "..." give the new Colour value. +* +* %c+ - Reset the Colour attribute to its "normal" value. +* +* %t...+ - Change the Style attribute for subsequent characters. The +* digits "..." give the new Style value. +* +* %t+ - Reset the Style attribute to its "normal" value. +* +* %h+ - Remember the current horizontal position (see "%g+") +* +* %g+ - Go to the horizontal position of the previous "%h+" (if any). +* +* %- - Push the current graphics attribute values onto the top of +* the stack (see "%+"). +* +* %+ - Pop attributes values of the top the stack (see "%-"). If +* the stack is empty, "normal" attribute values are restored. + +* Applicability: +* Plot +* All Plots have this attribute. +*att-- +*/ + +/* Has a value of -1 when not set yeilding a default of 1. */ +astMAKE_GET(Plot,Escape,int,1,(this->escape == -1 ? 1 : this->escape)) +astMAKE_CLEAR(Plot,Escape,escape,-1) +astMAKE_SET(Plot,Escape,int,escape,( value ? 1 : 0 )) +astMAKE_TEST(Plot,Escape,( this->escape != -1 )) + +/* LabelAt(axis). */ +/* -------------- */ +/* +*att++ +* Name: +* LabelAt(axis) + +* Purpose: +* Where to place numerical labels for a Plot + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* where numerical axis labels and associated tick marks are +* placed. It takes a separate value for each physical axis of a +* Plot so that, for instance, the setting "LabelAt(2)=10.0" +* specifies where the numerical labels and tick marks for the +* second axis should be drawn. +* +* For each axis, the LabelAt value gives the value on the other +* axis at which numerical labels and tick marks should be placed +c (remember that Plots suitable for use with astGrid may only +f (remember that Plots suitable for use with AST_GRID may only +* have two axes). For example, in a celestial (RA,Dec) coordinate +* system, LabelAt(1) gives a Dec value which defines a line (of +* constant Dec) along which the numerical RA labels and their +* associated tick marks will be drawn. Similarly, LabelAt(2) gives +* the RA value at which the Dec labels and ticks will be drawn. +* +* The default bahaviour is for the Plot to generate its own +* position for numerical labels and tick marks. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - The LabelAt value should use the same units as are used +* internally for storing coordinate values on the appropriate +* axis. For example, with a celestial coordinate system, the +* LabelAt value should be in radians, not hours or degrees. +* - Normally, the LabelAt value also determines where the lines +* representing coordinate axes will be drawn, so that the tick +* marks will lie on these lines (but also see the DrawAxes +* attribute). +* - In some circumstances, numerical labels and tick marks are +* drawn around the edges of the plotting area (see the Labelling +* attribute). In this case, the value of the LabelAt attribute is +* ignored. +*att-- +*/ +/* The constant value on the other axis at which to place labels for + each axis. */ +MAKE_CLEAR(LabelAt,labelat,AST__BAD,0) +MAKE_GET(LabelAt,double,AST__BAD,this->labelat[axis],0) +MAKE_SET(LabelAt,double,labelat,value,0) +MAKE_TEST(LabelAt,( this->labelat[axis] != AST__BAD ),0) + +MAKE_GET3(LabelAt,double,AST__BAD,this->ulblat[axis],0) +MAKE_SET3(LabelAt,double,ulblat,value,0) + +/* Centre(axis). */ +/* ------------ */ +/* A value at which to place a tick mark. Other ticks marks are spaced at +regular distances from this one. AST__BAD is stored if no value is supplied, +resulting in Plot choosing its own value. */ +MAKE_CLEAR(Centre,centre,AST__BAD,0) +MAKE_GET(Centre,double,AST__BAD,this->centre[axis],0) +MAKE_SET(Centre,double,centre,value,0) +MAKE_TEST(Centre,( this->centre[axis] != AST__BAD ),0) + +MAKE_GET3(Centre,double,AST__BAD,this->ucentre[axis],0) +MAKE_SET3(Centre,double,ucentre,value,0) + +/* Ink */ +/* --- */ +/* A protected attribute indicating if astGrid should draw using visible +ink. The unset value is -1, yeilding a default value of 1. */ +astMAKE_CLEAR(Plot,Ink,ink,-1) +astMAKE_GET(Plot,Ink,int,1,(this->ink == -1 ? 1 : this->ink)) +astMAKE_SET(Plot,Ink,int,ink,( value ? 1 : 0 )) +astMAKE_TEST(Plot,Ink,( this->ink != -1 )) + +/* Gap(axis). */ +/* ---------- */ +/* +*att++ +* Name: +* Gap(axis) + +* Purpose: +* Interval between linearly spaced major axis values of a Plot. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* the linear interval between the "major" axis values of a Plot, at +* which (for example) major tick marks are drawn. It takes a separate +* value for each physical axis of the Plot so that, for instance, +* the setting "Gap(2)=3.0" specifies the difference between adjacent major +* values along the second axis. The Gap attribute is only used when +* the LogTicks attribute indicates that the spacing between major axis +* values is to be linear. If major axis values are logarithmically spaced +* then the gap is specified using attribute LogGap. +* +* The Gap value supplied will usually be rounded to the nearest +* "nice" value, suitable (e.g.) for generating axis labels, before +* use. To avoid this "nicing" you should set an explicit format +* for the axis using the Format(axis) or Digits/Digits(axis) +* attribute. The default behaviour is for the Plot to generate its +* own Gap value when required, based on the range of axis values +* to be represented. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - The Gap value should use the same units as are used internally +* for storing coordinate values on the corresponding axis. For +* example, with a celestial coordinate system, the Gap value +* should be in radians, not hours or degrees. +* - If no axis is specified, (e.g. "Gap" instead of "Gap(2)"), +* then a "set" or "clear" operation will affect the attribute +* value of all the Plot axes, while a "get" or "test" operation +* will use just the Gap(1) value. +*att-- +*/ +/* The gap between tick marks on each axis. AST__BAD is stored if no +value has been supplied, resulting in default values being found. */ +MAKE_CLEAR(Gap,gap,AST__BAD,0) +MAKE_SET(Gap,double,gap,value,0) +MAKE_TEST(Gap,( this->gap[axis] != AST__BAD ),0) +MAKE_GET(Gap,double,AST__BAD,this->gap[axis],0) + +MAKE_SET3(Gap,double,ugap,value,0) +MAKE_GET3(Gap,double,AST__BAD,this->ugap[axis],0) + +/* LogGap(axis). */ +/* ---------- */ +/* +*att++ +* Name: +* LogGap(axis) + +* Purpose: +* Interval between major axis values of a Plot. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* the logarithmic interval between the "major" axis values of a Plot, at +* which (for example) major tick marks are drawn. It takes a separate +* value for each physical axis of the Plot so that, for instance, +* the setting "LogGap(2)=100.0" specifies the ratio between adjacent major +* values along the second axis. The LogGap attribute is only used when +* the LogTicks attribute indicates that the spacing between major axis +* values is to be logarithmic. If major axis values are linearly spaced +* then the gap is specified using attribute Gap. +* +* The LogGap value supplied will be rounded to the nearest power of 10. +* The reciprocal of the supplied value may be used if this is necessary +* to produce usable major axis values. If a zero or negative value is +* supplied, an error will be reported when the grid is drawn. The default +* behaviour is for the Plot to generate its own LogGap value when +* required, based on the range of axis values to be represented. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - The LogGap value is a ratio between axis values and is therefore +* dimensionless. +* - If no axis is specified, (e.g. "LogGap" instead of "LogGap(2)"), +* then a "set" or "clear" operation will affect the attribute +* value of all the Plot axes, while a "get" or "test" operation +* will use just the LogGap(1) value. +*att-- +*/ +/* The logarithmic gap between tick marks on each axis. AST__BAD is stored if + no value has been supplied, resulting in default values being found. */ +MAKE_CLEAR(LogGap,loggap,AST__BAD,0) +MAKE_SET(LogGap,double,loggap,value,0) +MAKE_TEST(LogGap,( this->loggap[axis] != AST__BAD ),0) +MAKE_GET(LogGap,double,AST__BAD,this->loggap[axis],0) + +MAKE_SET3(LogGap,double,uloggap,value,0) +MAKE_GET3(LogGap,double,AST__BAD,this->uloggap[axis],0) + +/* LogPlot. */ +/* ------- */ +/* +*att++ +* Name: +* LogPlot(axis) + +* Purpose: +* Map the plot logarithmically onto the screen? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of all graphics produced by +* the Plot, by determining whether the axes of the plotting surface +* are mapped logarithmically or linearly onto the base Frame of the +* FrameSet supplied when the Plot was constructed. It takes a separate +* value for each axis of the graphics coordinate system (i.e. the +* base Frame in the Plot) so that, for instance, the setting +* "LogPlot(2)=1" specifies that the second axis of the graphics +* coordinate system (usually the vertical axis) should be mapped +* logarithmically onto the second axis of the base Frame of the +* FrameSet supplied when the Plot was constructed. +* +* If the LogPlot value of a Plot axis is non-zero, it causes that +* axis to be mapped logarithmically, otherwise (the default) the axis +* is mapped linearly. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - The setting of the LogPlot attribute provides the default value +* for the related LogTicks attribute. By selecting suitable values for +* LogPlot and LogTicks, it is possible to have tick marks which are evenly +* spaced in value but which are mapped logarithmically onto the screen +* (and vice-versa). +* - An axis may only be mapped logarithmically if the visible part of +* the axis does not include the value zero. The visible part of the +* axis is that part which is mapped onto the plotting area, and is +* measured within the base Frame of the FrameSet which was supplied when +* the Plot was constructed. Any attempt to set LogPlot to a non-zero value +* will be ignored (without error) if the visible part of the axis +* includes the value zero +* - If no axis is specified, (e.g. "LogPlot" instead of +* "LogPlot(2)"), then a "set" or "clear" operation will affect the +* attribute value of all the Plot axes, while a "get" or "test" +* operation will use just the LogPlot(1) value. +*att-- +*/ +/* Are plot axes to be mapped logarithmically? Has a value of -1 when +not set yielding a value of 0 (no) for both axes. */ +MAKE_GET(LogPlot,int,0,( this->logplot[axis] == -1 ? 0 : this->logplot[axis] ),0) +MAKE_TEST(LogPlot,( this->logplot[axis] != -1 ),0) + +/* LogTicks. */ +/* ------- */ +/* +*att++ +* Name: +* LogTicks(axis) + +* Purpose: +* Space the major tick marks logarithmically? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* whether the major tick marks should be spaced logarithmically or +* linearly in axis value. It takes a separate value for each physical +* axis of the Plot so that, for instance, the setting "LogTicks(2)=1" +* specifies that the major tick marks on the second axis should be +* spaced logarithmically. +* +* If the LogTicks value for a physical axis is non-zero, the major +* tick marks on that axis will be spaced logarithmically (that is, +* there will be a constant ratio between the axis values at adjacent +* major tick marks). An error will be reported if the dynamic range of +* the axis (the ratio of the largest to smallest displayed axis value) +* is less than 10.0. If the LogTicks value is zero, the major tick marks +* will be evenly spaced (that is, there will be a constant difference +* between the axis values at adjacent major tick marks). The default is +* to produce logarithmically spaced tick marks if the corresponding +* LogPlot attribute is non-zero and the ratio of maximum axis value +* to minimum axis value is 100 or more. If either of these conditions +* is not met, the default is to produce linearly spaced tick marks. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - The setting of the LogTicks attribute does not affect the mapping +* of the plot onto the screen, which is controlled by attribute LogPlot. +* By selecting suitable values for LogPlot and LogTicks, it is possible to +* have tick marks which are evenly spaced in value but which are mapped +* logarithmically onto the screen (and vica-versa). +* - An error will be reported when drawing an annotated axis grid if +* the visible part of the physical axis includes the value zero. +* - If no axis is specified, (e.g. "LogTicks" instead of +* "LogTicks(2)"), then a "set" or "clear" operation will affect the +* attribute value of all the Plot axes, while a "get" or "test" +* operation will use just the LogTicks(1) value. +*att-- +*/ +/* Are ticksto be spaced logarithmically? Has a value of -1 when + not set, yeielding a default value equal to the corresponding + LogPlot value. */ +MAKE_CLEAR(LogTicks,logticks,-1,0) +MAKE_GET(LogTicks,int,0,( this->logticks[axis] == -1 ? astGetLogPlot(this,axis) : this->logticks[axis] ),0) +MAKE_TEST(LogTicks,( this->logticks[axis] != -1 ),0) +MAKE_SET(LogTicks,int,logticks,( value ? 1 : 0 ),0) + +MAKE_SET3(LogTicks,int,ulgtk,value,0) +MAKE_GET3(LogTicks,int,0,this->ulgtk[axis],0) + +/* LogLabel. */ +/* -------- */ +/* +*att++ +* Name: +* LogLabel(axis) + +* Purpose: +* Use exponential format for numerical axis labels? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* whether the numerical axis labels should be in normal decimal form +* or should be represented as 10 raised to the appropriate power. +* That is, an axis value of 1000.0 will be drawn as "1000.0" if +* LogLabel is zero, but as "10^3" if LogLabel is non-zero. If +* graphical escape sequences are supported (see attribute Escape), +* the power in such exponential labels will be drawn as a small +* superscript instead of using a "^" character to represent +* exponentiation. +* +* The default is to produce exponential labels if the major tick +* marks are logarithmically spaced (see the LogTicks attribute). + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - If no axis is specified, (e.g. "LogLabel" instead of +* "LogLabel(2)"), then a "set" or "clear" operation will affect the +* attribute value of all the Plot axes, while a "get" or "test" +* operation will use just the LogLabel(1) value. +*att-- +*/ +/* Are labels to be drawn as 10**x? Has a value of -1 when not set, yeielding + a default value equal to the corresponding LogTicks value. */ +MAKE_CLEAR(LogLabel,loglabel,-1,0) +MAKE_GET(LogLabel,int,0,( this->loglabel[axis] == -1 ? astGetLogTicks(this,axis) : this->loglabel[axis] ),0) +MAKE_TEST(LogLabel,( this->loglabel[axis] != -1 ),0) +MAKE_SET(LogLabel,int,loglabel,( value ? 1 : 0 ),0) + +MAKE_SET3(LogLabel,int,ulglb,value,0) +MAKE_GET3(LogLabel,int,0,this->ulglb[axis],0) + +/* MajTickLen. */ +/* ----------- */ +/* +*att++ +* Name: +* MajTickLen(axis) + +* Purpose: +* Length of major tick marks for a Plot. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* the length of the major tick marks drawn on the axes of a Plot. +* It takes a separate value for each physical axis of the Plot so +* that, for instance, the setting "MajTickLen(2)=0" specifies the +* length of the major tick marks drawn on the second axis. +* +* The MajTickLen value should be given as a fraction of the +* minimum dimension of the plotting area. Negative values cause +* major tick marks to be placed on the outside of the +* corresponding grid line or axis (but subject to any clipping +* imposed by the underlying graphics system), while positive +* values cause them to be placed on the inside. +* +* The default behaviour depends on whether a coordinate grid is +* drawn inside the plotting area (see the Grid attribute). If so, +* the default MajTickLen value is zero (so that major ticks are +* not drawn), otherwise the default is +0.015. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - If no axis is specified, (e.g. "MajTickLen" instead of +* "MajTickLen(2)"), then a "set" or "clear" operation will affect +* the attribute value of all the Plot axes, while a "get" or "test" +* operation will use just the MajTickLen(1) value. + +*att-- +*/ +/* Fractional length of major tick marks. Has a value of AST__BAD when not +set yielding a default value of 0.015. */ +MAKE_CLEAR(MajTickLen,majticklen,AST__BAD,0) +MAKE_SET(MajTickLen,double,majticklen,value,0) +MAKE_TEST(MajTickLen,( this->majticklen[axis] != AST__BAD ),0) +MAKE_GET(MajTickLen,double,0.0,( this->majticklen[axis] == AST__BAD ? 0.015 : this->majticklen[axis]),0) + +MAKE_SET3(MajTickLen,double,umjtkln,value,0) +MAKE_GET3(MajTickLen,double,0.0,this->umjtkln[axis],0) + +/* TitleGap. */ +/* --------- */ +/* +*att++ +* Name: +* TitleGap + +* Purpose: +* Vertical spacing for a Plot title. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* where the title of a Plot is drawn. +* +* Its value gives the spacing between the bottom edge of the title +* and the top edge of a bounding box containing all the other parts +* of the annotated grid. Positive values cause the title to be +* drawn outside the box, while negative values cause it to be drawn +* inside. +* +* The TitleGap value should be given as a fraction of the minimum +* dimension of the plotting area, the default value being +0.05. + +* Applicability: +* Plot +* All Plots have this attribute. +* Plot3D +* The Plot3D class ignores this attributes since it does not draw +* a Title. + +* Notes: +* - The text used for the title is obtained from the Plot's Title +* attribute. +*att-- +*/ +/* Fractional gap between titile and top edge. Has a value of AST__BAD when +not set yielding a default value of 0.05. */ +astMAKE_CLEAR(Plot,TitleGap,titlegap,AST__BAD) +astMAKE_GET(Plot,TitleGap,double,0.0,( this->titlegap == AST__BAD ? 0.05 : this->titlegap)) +astMAKE_SET(Plot,TitleGap,double,titlegap,value) +astMAKE_TEST(Plot,TitleGap,( this->titlegap != AST__BAD )) + +/* MinTickLen. */ +/* ----------- */ +/* +*att++ +* Name: +* MinTickLen(axis) + +* Purpose: +* Length of minor tick marks for a Plot. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* the length of the minor tick marks drawn on the axes of a Plot. +* It takes a separate value for each physical axis of the Plot so +* that, for instance, the setting "MinTickLen(2)=0" specifies the +* length of the minor tick marks drawn on the second axis. +* +* The MinTickLen value should be given as a fraction of the +* minimum dimension of the plotting area. Negative values cause +* minor tick marks to be placed on the outside of the +* corresponding grid line or axis (but subject to any clipping +* imposed by the underlying graphics system), while positive +* values cause them to be placed on the inside. +* +* The default value is +0.007. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - The number of minor tick marks drawn is determined by the +* Plot's MinTick(axis) attribute. +* - If no axis is specified, (e.g. "MinTickLen" instead of +* "MinTickLen(2)"), then a "set" or "clear" operation will affect +* the attribute value of all the Plot axes, while a "get" or "test" +* operation will use just the MinTickLen(1) value. + +*att-- +*/ +/* Fractional length of minor tick marks. Has a value of AST__BAD when not +set yielding a default value of 0.007. */ +MAKE_CLEAR(MinTickLen,minticklen,AST__BAD,0) +MAKE_SET(MinTickLen,double,minticklen,value,0) +MAKE_TEST(MinTickLen,( this->minticklen[axis] != AST__BAD ),0) +MAKE_GET(MinTickLen,double,0.0,( this->minticklen[axis] == AST__BAD ? 0.007 : this->minticklen[axis]),0) + +/* Labelling. */ +/* ---------- */ +/* +*att++ +* Name: +* Labelling + +* Purpose: +* Label and tick placement option for a Plot. + +* Type: +* Public attribute. + +* Synopsis: +* String. + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* the strategy for placing numerical labels and tick marks for a Plot. +* +* If the Labelling value of a Plot is "exterior" (the default), then +* numerical labels and their associated tick marks are placed +* around the edges of the plotting area, if possible. If this is +* not possible, or if the Labelling value is "interior", then they +* are placed along grid lines inside the plotting area. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - The LabelAt(axis) attribute may be used to determine the exact +* placement of labels and tick marks that are drawn inside the +* plotting area. +*att-- +*/ +astMAKE_CLEAR(Plot,Labelling,labelling,-9999) +astMAKE_SET(Plot,Labelling,int,labelling,(value?1:0)) +astMAKE_TEST(Plot,Labelling,( this->labelling != -9999 )) +astMAKE_GET(Plot,Labelling,int,0,(this->labelling == -9999 ? 0 : this->labelling)) + +MAKE_SET2(Plot,Labelling,int,ulbling,(value?1:0)) +MAKE_GET2(Plot,Labelling,int,0,this->ulbling) + +/* Edge. */ +/* ----- */ +/* +*att++ +* Name: +* Edge(axis) + +* Purpose: +* Which edges to label in a Plot + +* Type: +* Public attribute. + +* Synopsis: +* String. + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* which edges of a Plot are used for displaying numerical and +* descriptive axis labels. It takes a separate value for each +* physical axis of the Plot so that, for instance, the setting +* "Edge(2)=left" specifies which edge to use to display labels for +* the second axis. +* +* The values "left", "top", "right" and "bottom" (or any +* abbreviation) can be supplied for this attribute. The default is +* usually "bottom" for the first axis and "left" for the second +* axis. However, if exterior labelling was requested (see the +* Labelling attribute) but cannot be produced using these default +* Edge values, then the default values will be swapped if this +* enables exterior labelling to be produced. + +* Applicability: +* Plot +* All Plots have this attribute. +* Plot3D +* The Plot3D class ignores this attributes. Instead it uses its +* own RootCorner attribute to determine which edges of the 3D plot +* to label. + +* Notes: +* - In some circumstances, numerical labels will be drawn along +* internal grid lines instead of at the edges of the plotting area +* (see the Labelling attribute). In this case, the Edge attribute +* only affects the placement of the descriptive labels (these are +* drawn at the edges of the plotting area, rather than along the +* axis lines). +*att-- +*/ +/* The edges of the plotting area on which to place numerical labels + for axes 0 and 1. Has a value of -1 when not set yielding a value + of 3 (the bottom edge) for axis 0 and 0 (the left-hand edge) for + axis 1. */ +MAKE_CLEAR(Edge,edge,-1,0) +MAKE_GET(Edge,int,0,( this->edge[axis] == -1 ? (axis?LEFT:BOTTOM) : this->edge[axis] ),0) +MAKE_SET(Edge,int,edge,(abs( value % 4 )),0) +MAKE_TEST(Edge,( this->edge[axis] != -1 ),0) + +MAKE_GET3(Edge,int,0,this->uedge[axis],0) +MAKE_SET3(Edge,int,uedge,(abs( value % 4 )),0) + +/* NumLab. */ +/* -------- */ +/* +*att++ +* Name: +* NumLab(axis) + +* Purpose: +* Draw numerical axis labels for a Plot? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* whether labels should be drawn to represent the numerical values +* along each axis of a Plot. It takes a separate value for each +* physical axis of a Plot so that, for instance, the setting +* "NumLab(2)=1" specifies that numerical labels should be drawn +* for the second axis. +* +* If the NumLab value of a Plot axis is non-zero (the default), +* then numerical labels will be drawn for that axis, otherwise +* they will be omitted. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - The drawing of associated descriptive axis labels for a Plot +* (describing the quantity being plotted along each axis) is +* controlled by the TextLab(axis) attribute. +* - If no axis is specified, (e.g. "NumLab" instead of +* "NumLab(2)"), then a "set" or "clear" operation will affect the +* attribute value of all the Plot axes, while a "get" or "test" +* operation will use just the NumLab(1) value. +*att-- +*/ +/* Are numerical labels to be displayed on each axis? Has a value of + -1 when not set yielding a value of 1 (yes) for both axes. */ +MAKE_CLEAR(NumLab,numlab,-1,0) +MAKE_GET(NumLab,int,1,( this->numlab[axis] == -1 ? 1 : this->numlab[axis] ),0) +MAKE_TEST(NumLab,( this->numlab[axis] != -1 ),0) +MAKE_SET(NumLab,int,numlab,( value ? 1 : 0 ),0) + +/* NumLabGap. */ +/* --------- */ +/* +*att++ +* Name: +* NumLabGap(axis) + +* Purpose: +* Spacing of numerical labels for a Plot. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* where numerical axis labels are placed relative to the axes they +* describe. It takes a separate value for each physical axis of a +* Plot so that, for instance, the setting "NumLabGap(2)=-0.01" +* specifies where the numerical label for the second axis should +* be drawn. +* +* For each axis, the NumLabGap value gives the spacing between the +* axis line (or edge of the plotting area, if appropriate) and the +* nearest edge of the corresponding numerical axis +* labels. Positive values cause the descriptive label to be placed +* on the opposite side of the line to the default tick marks, +* while negative values cause it to be placed on the same side. +* +* The NumLabGap value should be given as a fraction of the minimum +* dimension of the plotting area, the default value being +0.01. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - If no axis is specified, (e.g. "NumLabGap" instead of +* "NumLabGap(2)"), then a "set" or "clear" operation will affect +* the attribute value of all the Plot axes, while a "get" or +* "test" operation will use just the NumLabGap(1) value. +*att-- +*/ +/* Fractional spacing between numeric labels and axes. Has a value of AST__BAD +when not set yielding a default value of 0.01. */ +MAKE_CLEAR(NumLabGap,numlabgap,AST__BAD,0) +MAKE_GET(NumLabGap,double,0.0,( this->numlabgap[ axis ] == AST__BAD ? 0.01 : this->numlabgap[axis]),0) +MAKE_SET(NumLabGap,double,numlabgap,value,0) +MAKE_TEST(NumLabGap,( this->numlabgap[axis] != AST__BAD ),0) + +/* MinTick. */ +/* -------- */ +/* +*att++ +* Name: +* MinTick(axis) + +* Purpose: +* Density of minor tick marks for a Plot. + +* Type: +* Public attribute. + +* Synopsis: +* Integer. + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* the density of minor tick marks which appear between the major +* axis values of a Plot. It takes a separate value for each +* physical axis of a Plot so that, for instance, the setting +* "MinTick(2)=2" specifies the density of minor tick marks along +* the second axis. +* +* The value supplied should be the number of minor divisions +* required between each pair of major axis values, this being one +* more than the number of minor tick marks to be drawn. By +* default, a value is chosen that depends on the gap between major +* axis values and the nature of the axis. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - If no axis is specified, (e.g. "MinTick" instead of +* "MinTick(2)"), then a "set" or "clear" operation will affect +* the attribute value of all the Plot axes, while a "get" or +* "test" operation will use just the MinTick(1) value. +*att-- +*/ +/* How many divisions are there between major tick marks? Has a value +of -1 when not set yielding a value of 1 for both axes. */ +MAKE_CLEAR(MinTick,mintick,-1,0) +MAKE_GET(MinTick,int,1,( this->mintick[axis] == -1 ? 1 : this->mintick[axis] ),0) +MAKE_TEST(MinTick,( this->mintick[axis] != -1 ),0) +MAKE_SET(MinTick,int,mintick,( (value < 1)? 1 : value ),0) + +MAKE_GET3(MinTick,int,1,this->umintk[axis],0) +MAKE_SET3(MinTick,int,umintk,( (value < 1)? 1 : value ),0) + +/* TextLab. */ +/* --------- */ +/* +*att++ +* Name: +* TextLab(axis) + +* Purpose: +* Draw descriptive axis labels for a Plot? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* whether textual labels should be drawn to describe the quantity +* being represented on each axis of a Plot. It takes a separate +* value for each physical axis of a Plot so that, for instance, +* the setting "TextLab(2)=1" specifies that descriptive labels +* should be drawn for the second axis. +* +* If the TextLab value of a Plot axis is non-zero, then +* descriptive labels will be drawn for that axis, otherwise they +* will be omitted. The default behaviour is to draw descriptive +* labels if tick marks and numerical labels are being drawn around +* the edges of the plotting area (see the Labelling attribute), +* but to omit them otherwise. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - The text used for the descriptive labels is derived from the +* Plot's Label(axis) attribute, together with its Unit(axis) +* attribute if appropriate (see the LabelUnits(axis) attribute). +* - The drawing of numerical axis labels for a Plot (which +* indicate values on the axis) is controlled by the NumLab(axis) +* attribute. +* - If no axis is specified, (e.g. "TextLab" instead of +* "TextLab(2)"), then a "set" or "clear" operation will affect +* the attribute value of all the Plot axes, while a "get" or +* "test" operation will use just the TextLab(1) value. +*att-- +*/ +/* Are textual labels to be displayed on each axis? Has a value of -1 + when not set yielding a value of 1 (yes) for both axes. */ +MAKE_CLEAR(TextLab,textlab,-1,0) +MAKE_GET(TextLab,int,1,( this->textlab[axis] == -1 ? 1 : this->textlab[axis] ),0) +MAKE_TEST(TextLab,( this->textlab[axis] != -1 ),0) +MAKE_SET(TextLab,int,textlab,( value ? 1 : 0 ),0) + +MAKE_GET3(TextLab,int,1,this->utxtlb[axis],0) +MAKE_SET3(TextLab,int,utxtlb,( value ? 1 : 0 ),0) + +/* TextLabGap. */ +/* ----------- */ +/* +*att++ +* Name: +* TextLabGap(axis) + +* Purpose: +* Spacing of descriptive axis labels for a Plot. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* where descriptive axis labels are placed relative to the axes they +* describe. It takes a separate value for each physical axis of a +* Plot so that, for instance, the setting "TextLabGap(2)=0.01" +* specifies where the descriptive label for the second axis should +* be drawn. +* +* For each axis, the TextLabGap value gives the spacing between the +* descriptive label and the edge of a box enclosing all other parts +* of the annotated grid (excluding other descriptive labels). The gap +* is measured to the nearest edge of the label (i.e. the top or the +* bottom). Positive values cause the descriptive label to be placed +* outside the bounding box, while negative values cause it to be placed +* inside. +* +* The TextLabGap value should be given as a fraction of the minimum +* dimension of the plotting area, the default value being +0.01. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - If drawn, descriptive labels are always placed at the edges of +* the plotting area, even although the corresponding numerical +* labels may be drawn along axis lines in the interior of the +* plotting area (see the Labelling attribute). +* - If no axis is specified, (e.g. "TextLabGap" instead of +* "TextLabGap(2)"), then a "set" or "clear" operation will affect +* the attribute value of all the Plot axes, while a "get" or +* "test" operation will use just the TextLabGap(1) value. +*att-- +*/ +/* Fractional spacing between numeric labels and axes. Has a value of AST__BAD +when not set yielding a default value of 0.01. */ +MAKE_CLEAR(TextLabGap,textlabgap,AST__BAD,0) +MAKE_GET(TextLabGap,double,0.0,( this->textlabgap[ axis ] == AST__BAD ? 0.01 : this->textlabgap[axis]),0) +MAKE_SET(TextLabGap,double,textlabgap,value,0) +MAKE_TEST(TextLabGap,( this->textlabgap[axis] != AST__BAD ),0) + +/* LabelUnits. */ +/* ----------- */ +/* +*att++ +* Name: +* LabelUnits(axis) + +* Purpose: +* Use axis unit descriptions in a Plot? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls the appearance of an annotated +c coordinate grid (drawn with the astGrid function) by determining +f coordinate grid (drawn with the AST_GRID routine) by determining +* whether the descriptive labels drawn for each axis of a Plot +* should include a description of the units being used on the +* axis. It takes a separate value for each physical axis of a +* Plot so that, for instance, the setting "LabelUnits(2)=1" +* specifies that a unit description should be included in the +* label for the second axis. +* +* If the LabelUnits value of a Plot axis is non-zero, a unit +* description will be included in the descriptive label for that +* axis, otherwise it will be omitted. The default behaviour is to +* include a unit description unless the current Frame of the Plot +* is a SkyFrame representing equatorial, ecliptic, galactic or +* supergalactic coordinates, in which case it is omitted. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - The text used for the unit description is obtained from the +* Plot's Unit(axis) attribute. +* - If no axis is specified, (e.g. "LabelUnits" instead of +* "LabelUnits(2)"), then a "set" or "clear" operation will affect +* the attribute value of all the Plot axes, while a "get" or +* "test" operation will use just the LabelUnits(1) value. +* - If the current Frame of the Plot is not a SkyFrame, but includes +* axes which were extracted from a SkyFrame, then the default behaviour +* is to include a unit description only for those axes which were not +* extracted from a SkyFrame. +*att-- +*/ +/* Are textual labels to include a string describing the axis units? Has a +value of -1 when not set yielding a default of 1. */ +MAKE_CLEAR(LabelUnits,labelunits,-1,0) +MAKE_TEST(LabelUnits,( this->labelunits[axis] != -1 ),0) +MAKE_SET(LabelUnits,int,labelunits,( value ? 1 : 0 ),0) + +MAKE_GET3(LabelUnits,int,1,this->ulbunit[axis],0) +MAKE_SET3(LabelUnits,int,ulbunit,( value ? 1 : 0 ),0) + +/* Style. */ +/* ------ */ +/* +*att++ +* Name: +* Style(element) + +* Purpose: +* Line style for a Plot element. + +* Type: +* Public attribute. + +* Synopsis: +* Integer. + +* Description: +* This attribute determines the line style used when drawing each +* element of graphical output produced by a Plot. It takes a +* separate value for each graphical element so that, for instance, +* the setting "Style(border)=2" causes the Plot border to be drawn +* using line style 2 (which might result in, say, a dashed line). +* +* The range of integer line styles available and their appearance +* is determined by the underlying graphics system. The default +* behaviour is for all graphical elements to be drawn using the +* default line style supplied by this graphics system (normally, +* this is likely to give a solid line). + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - For a list of the graphical elements available, see the +* description of the Plot class. +* - If no graphical element is specified, (e.g. "Style" instead of +* "Style(border)"), then a "set" or "clear" operation will affect +* the attribute value of all graphical elements, while a "get" or +* "test" operation will use just the Style(Border) value. +*att-- +*/ +/* Line styles. Has a value of -1 when not set yielding a default of 1. */ +MAKE_CLEAR(Style,style,-1,AST__NPID) +MAKE_GET(Style,int,1,( this->style[axis] == -1 ? 1 : this->style[axis] ),AST__NPID) +MAKE_TEST(Style,( this->style[axis] != -1 ),AST__NPID) +MAKE_SET(Style,int,style,value,AST__NPID) + +/* Font. */ +/* ----- */ +/* +*att++ +* Name: +* Font(element) + +* Purpose: +* Character font for a Plot element. + +* Type: +* Public attribute. + +* Synopsis: +* Integer. + +* Description: +* This attribute determines the character font index used when +* drawing each element of graphical output produced by a Plot. It +* takes a separate value for each graphical element so that, for +* instance, the setting "Font(title)=2" causes the Plot title to +* be drawn using font number 2. +* +* The range of integer font indices available and the appearance +* of the resulting text is determined by the underlying graphics +* system. The default behaviour is for all graphical elements to +* be drawn using the default font supplied by this graphics +* system. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - For a list of the graphical elements available, see the +* description of the Plot class. +* - If no graphical element is specified, (e.g. "Font" instead +* of "Font(title)"), then a "set" or "clear" operation will +* affect the attribute value of all graphical elements, while a +* "get" or "test" operation will use just the Font(TextLab) +* value. +*att-- +*/ +/* Character fonts. Has a value of -1 when not set yielding a default of 1. */ +MAKE_CLEAR(Font,font,-1,AST__NPID) +MAKE_GET(Font,int,1,( this->font[axis] == -1 ? 1 : this->font[axis] ),AST__NPID) +MAKE_TEST(Font,( this->font[axis] != -1 ),AST__NPID) +MAKE_SET(Font,int,font,value,AST__NPID) + +/* Colour. */ +/* ------- */ +/* +*att++ +* Name: +* Colour(element) + +* Purpose: +* Colour index for a Plot element. + +* Type: +* Public attribute. + +* Synopsis: +* Integer. + +* Description: +* This attribute determines the colour index used when drawing +* each element of graphical output produced by a Plot. It takes a +* separate value for each graphical element so that, for instance, +* the setting "Colour(title)=2" causes the Plot title to be drawn +* using colour index 2. The synonym "Color" may also be used. +* +* The range of integer colour indices available and their +* appearance is determined by the underlying graphics system. The +* default behaviour is for all graphical elements to be drawn +* using the default colour index supplied by this graphics system +* (normally, this is likely to result in white plotting on a black +* background, or vice versa). +d +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - For a list of the graphical elements available, see the +* description of the Plot class. +* - If no graphical element is specified, (e.g. "Colour" instead +* of "Colour(title)"), then a "set" or "clear" operation will +* affect the attribute value of all graphical elements, while a +* "get" or "test" operation will use just the Colour(TextLab) +* value. +*att-- +*/ +/* Colours. Has a value of -1 when not set yielding a default of 1. */ +MAKE_CLEAR(Colour,colour,-1,AST__NPID) +MAKE_GET(Colour,int,1,( this->colour[axis] == -1 ? 1 : this->colour[axis] ),AST__NPID) +MAKE_TEST(Colour,( this->colour[axis] != -1 ),AST__NPID) +MAKE_SET(Colour,int,colour,value,AST__NPID) + +/* Width. */ +/* ------ */ +/* +*att++ +* Name: +* Width(element) + +* Purpose: +* Line width for a Plot element. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute determines the line width used when drawing each +* element of graphical output produced by a Plot. It takes a +* separate value for each graphical element so that, for instance, +* the setting "Width(border)=2.0" causes the Plot border to be +* drawn using a line width of 2.0. A value of 1.0 results in a +* line thickness which is approximately 0.0005 times the length of +* the diagonal of the entire display surface. +* +* The actual appearance of lines drawn with any particular width, +* and the range of available widths, is determined by the +* underlying graphics system. The default behaviour is for all +* graphical elements to be drawn using the default line width +* supplied by this graphics system. This will not necessarily +* correspond to a Width value of 1.0. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - For a list of the graphical elements available, see the +* description of the Plot class. +* - If no graphical element is specified, (e.g. "Width" instead of +* "Width(border)"), then a "set" or "clear" operation will affect +* the attribute value of all graphical elements, while a "get" or +* "test" operation will use just the Width(Border) value. +*att-- +*/ +/* Line widths. Has a value of AST__BAD when not set yielding a + default of 1.0. */ +MAKE_CLEAR(Width,width,AST__BAD,AST__NPID) +MAKE_GET(Width,double,1.0,( this->width[axis] == AST__BAD ? 1.0 : this->width[axis] ),AST__NPID) +MAKE_TEST(Width,( this->width[axis] != AST__BAD ),AST__NPID) +MAKE_SET(Width,double,width,(value!=0.00)?value:(astError(AST__ATTIN,"astSetWidth(Plot):Invalid zero value supplied for Width(%s) attribute", status,GrfItem(axis,NULL,NULL, status )),this->width[axis]),AST__NPID) + +/* Size. */ +/* ----- */ +/* +*att++ +* Name: +* Size(element) + +* Purpose: +* Character size for a Plot element. + +* Type: +* Public attribute. + +* Synopsis: +* Floating Point. + +* Description: +* This attribute determines the character size used when drawing +* each element of graphical output produced by a Plot. It takes a +* separate value for each graphical element so that, for instance, +* the setting "Size(title)=2.0" causes the Plot title to be drawn +* using twice the default character size. +* +* The range of character sizes available and the appearance of the +* resulting text is determined by the underlying graphics system. +* The default behaviour is for all graphical elements to be drawn +* using the default character size supplied by this graphics +* system. + +* Applicability: +* Plot +* All Plots have this attribute. + +* Notes: +* - For a list of the graphical elements available, see the +* description of the Plot class. +* - If no graphical element is specified, (e.g. "Size" instead +* of "Size(title)"), then a "set" or "clear" operation will +* affect the attribute value of all graphical elements, while a +* "get" or "test" operation will use just the Size(TextLab) +* value. +*att-- +*/ +/* Character sizes. Has a value of AST__BAD when not set yielding a default + of 1.0. */ +MAKE_CLEAR(Size,size,AST__BAD,AST__NPID) +MAKE_GET(Size,double,1.0,( this->size[axis] == AST__BAD ? 1.0 : this->size[axis] ),AST__NPID) +MAKE_TEST(Size,( this->size[axis] != AST__BAD ),AST__NPID) +MAKE_SET(Size,double,size,(value!=0.00)?value:(astError(AST__ATTIN,"astSetSize(Plot): Invalid zero value supplied for Size(%s) attribute", status,GrfItem(axis,NULL,NULL, status )),this->size[axis]),AST__NPID) + +/* Member functions. */ +/* ================= */ +static void AddCdt( AstPlotCurveData *cdt1, AstPlotCurveData *cdt2, const char *method, + const char *class, int *status ){ +/* +* +* Name: +* AddCdt + +* Purpose: +* Append one AstPlotCurveData structure to another. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void AddCdt( AstPlotCurveData *cdt1, AstPlotCurveData *cdt2, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* The contents of the structure pointed to by "cdt2" is appended +* to the structure pointed to by "cdt1". + +* Parameters: +* cdt1 +* Pointer to the AstPlotCurveData structure to be modified. +* cdt2 +* Pointer to the AstPlotCurveData structure to be appended to cdt1. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Notes: +* - An error is reported if there is insufficient room in "cdt1" to +* store the information in "cdt2". + +*/ + +/* Local Variables: */ + int nbrk, i, j; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get the total number of breaks described by both structures. */ + nbrk = cdt1->nbrk + cdt2->nbrk; + +/* Report an error if this number of breaks cannot be stored in a AstPlotCurveData + structure. */ + if( nbrk > AST__MXBRK ){ + astError( AST__CVBRK, "%s(%s): Number of breaks in curve " + "exceeds %d.", status, method, class, AST__MXBRK ); + +/* Otherwise, append the information. */ + } else { + +/* Store the index within "cdt1" of the next break to be added. */ + j = cdt1->nbrk; + +/* Add each the position and direction information for each of the breaks + in "cdt2". */ + for( i = 0; i < cdt2->nbrk; i++ ){ + cdt1->xbrk[ j ] = cdt2->xbrk[ i ]; + cdt1->ybrk[ j ] = cdt2->ybrk[ i ]; + cdt1->vxbrk[ j ] = cdt2->vxbrk[ i ]; + cdt1->vybrk[ j ] = cdt2->vybrk[ i ]; + +/* Increment the index of the next break in "cdt1". */ + j++; + } + +/* Update the number of breaks in "cdt1". */ + cdt1->nbrk = nbrk; + +/* Update the length of the curve described by "cdt1". */ + cdt1->length += cdt2->length; + +/* Update the flag indicating if the entire curve is outside the plotting + zone. */ + if( !cdt2->out ) cdt1->out = 0; + + } + +/* Return. */ + return; + +} + +static void Apoly( AstPlot *this, float x, float y, int *status ){ +/* +* Name: +* Apoly + +* Purpose: +* Append a another point to a poly line. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Apoly( AstPlot *this, float x, float y, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function appends the supplied point to the current poly line. + +* Parameters: +* x +* The graphics x coordinate. +* y +* The graphics y coordinate. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + int ipoint; + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + +/* Check the global status. */ + if( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Extend the buffers, and add the supplied point to the end. */ + ipoint = Poly_n++; + Poly_x = astGrow( Poly_x, Poly_n, sizeof(*Poly_x) ); + Poly_y = astGrow( Poly_y, Poly_n, sizeof(*Poly_y) ); + if( astOK ) { + Poly_x[ ipoint ] = x; + Poly_y[ ipoint ] = y; + } + +/* Update the box containing all plotted lines. */ + Box_lbnd[ 0 ] = astMIN( x, Box_lbnd[ 0 ] ); + Box_ubnd[ 0 ] = astMAX( x, Box_ubnd[ 0 ] ); + Box_lbnd[ 1 ] = astMIN( y, Box_lbnd[ 1 ] ); + Box_ubnd[ 1 ] = astMAX( y, Box_ubnd[ 1 ] ); + +} + +static void AxPlot( AstPlot *this, int axis, const double *start, double length, + int ink, AstPlotCurveData *cdata, const char *method, const char *class, int *status ){ +/* +* +* Name: +* AxPlot + +* Purpose: +* Draw a curve with constant axis value. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void AxPlot( AstPlot *this, int axis, const double *start, double length, +* int ink, AstPlotCurveData *cdata, const char *method, const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function draws a section of a curve of the specified length +* with constant value on a specified axis in the current Frame of the +* Plot, starting at the specified position. The algorithm used can handle +* discontinuities in the Mapping between the current Frame and graphics +* coordinates, and information describing any breaks in the curve +* (including the start and end of the curve) are returned in the supplied +* AstPlotCurveData structure. + +* Parameters: +* this +* Pointer to the Plot. +* axis +* The zero-based index of an axis within the current Frame of the Plot. +* The curve has a varying value on this axis. +* start +* A pointer to a an array holding the coordinates of the start of the +* curve within the current Frame of the Plot. +* length +* The length of the section of the curve to be drawn, given as an +* increment along the axis specified by parameter "axis". +* ink +* If zero, the curve is not actually drawn, but information about +* the breaks is still returned. If non-zero, the curve is also drawn. +* cdata +* A pointer to a structure in which to return information about the +* breaks in the curve. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Notes: +* - No curve is draw if the "start" array contains any bad values +* (i.e. values equal to AST__BAD), or if the "length" value is bad, +* or if a NULL pointer is supplied for "cdata". No errors are reported +* in these cases. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + double d[ CRV_NPNT ]; /* Offsets to evenly spaced points along curve */ + double x[ CRV_NPNT ]; /* X coords at evenly spaced points along curve */ + double y[ CRV_NPNT ]; /* Y coords at evenly spaced points along curve */ + double tol; /* Absolute tolerance value */ + int i; /* Loop count */ + int naxes; /* No. of axes in the base Frame */ + int ok; /* Are all start coords good? */ + int gridid; /* Identifier value for element being drawn */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +#ifdef CRV_TRACE + printf("AXPLOT: axis %d, start (%.*g,%.*g), length %.*g\n", + axis, DBL_DIG, start[0], DBL_DIG, start[1], DBL_DIG, length ); + getchar(); +#endif + + +/* Initialise any supplied cdata structure to hold safe values. */ + if( cdata ){ + cdata->length = 0.0; + cdata->out = 1; + cdata->nbrk = 0; + } + +/* Get the number of axes in the current Frame. */ + naxes = astGetNout( this ); + +/* Check the "start" parameter for bad values. */ + ok = 1; + for( i = 0; i < naxes; i++ ) { + if( start[ i ] == AST__BAD ){ + ok = 0; + break; + } + } + +/* Check the "length" parameter for bad values. */ + if( length == AST__BAD ) ok = 0; + +/* Check that the "cdata" pointer can be used. */ + if( !cdata ) ok = 0; + +/* Only proceed if the parameters are OK, and there has been no error. */ + if( ok && astOK ){ + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + if( axis == 0 ) { + gridid = AST__GRIDLINE2_ID; + } else { + gridid = AST__GRIDLINE1_ID; + } + astGrfAttrs( this, gridid, 1, GRF__LINE, method, class ); + +/* Ensure the globals holding the scaling from graphics coords to equally + scaled coords are available. */ + GScales( this, NULL, NULL, method, class, status ); + +/* Set up the externals used to communicate with the Map1 function... + The number of axes in the physical coordinate system (i.e. the current + Frame). */ + Map1_ncoord = naxes; + +/* See if tick marks are logarithmically or linearly spaced. */ + Map1_log = astGetLogTicks( this, axis ); + +/* A pointer to the Plot, the Current Frame and the Mapping. */ + Map1_plot = this; + Map1_frame = astGetFrame( this, AST__CURRENT ); + Map1_map = astGetMapping( this, AST__BASE, AST__CURRENT ); + +/* Physical coords at the start of the curve (dist=0). */ + Map1_origin = start; + +/* Length of the curve. */ + Map1_length = length; + +/* The index of the axis which the curve follows. */ + Map1_axis = axis; + +/* Decide whether to omit points not in their normal ranges. */ + Map1_norm = !IsASkyAxis( Map1_frame, 0, status ) && + !IsASkyAxis( Map1_frame, 1, status ); + +/* Convert the tolerance from relative to absolute graphics coordinates. */ + tol = astGetTol( this )*astMAX( this->xhi - this->xlo, + this->yhi - this->ylo ); + +/* Now set up the external variables used by the Crv and CrvLine function. */ + Crv_scerr = ( astGetLogPlot( this, 0 ) || + astGetLogPlot( this, 1 ) ) ? 100.0 : 1.5; + Crv_ux0 = AST__BAD; + Crv_tol = tol; + Crv_limit = 0.5*tol*tol; + Crv_map = Map1; + Crv_ink = ink; + Crv_xlo = this->xlo; + Crv_xhi = this->xhi; + Crv_ylo = this->ylo; + Crv_yhi = this->yhi; + Crv_out = 1; + Crv_xbrk = cdata->xbrk; + Crv_ybrk = cdata->ybrk; + Crv_vxbrk = cdata->vxbrk; + Crv_vybrk = cdata->vybrk; + Crv_clip = astGetClip( this ) & 1; + +/* Set up a list of points spread evenly over the curve. */ + for( i = 0; i < CRV_NPNT; i++ ){ + d[ i ] = ( (double) i)/( (double) CRV_NSEG ); + } + +/* Map these points into graphics coordinates. */ + Map1( CRV_NPNT, d, x, y, method, class, status GLOBALS_NAME ); + +/* Use Crv and Map1 to draw the curve. */ + Crv( this, d, x, y, 0, NULL, NULL, method, class, status ); + +/* End the current poly line. */ + Opoly( this, status ); + +/* Tidy up the static data used by Map1. */ + Map1( 0, NULL, NULL, NULL, method, class, status GLOBALS_NAME ); + +/* If no part of the curve could be drawn, set the number of breaks and the + length of the drawn curve to zero. */ + if( Crv_out ) { + Crv_nbrk = 0; + Crv_len = 0.0F; + +/* Otherwise, add an extra break to the returned structure at the position of + the last point to be plotted. */ + } else { + Crv_nbrk++; + if( Crv_nbrk > AST__PLOT_CRV_MXBRK ){ + astError( AST__CVBRK, "%s(%s): Number of breaks in curve " + "exceeds %d.", status, method, class, AST__PLOT_CRV_MXBRK ); + } else { + *(Crv_xbrk++) = (float) Crv_xl; + *(Crv_ybrk++) = (float) Crv_yl; + *(Crv_vxbrk++) = (float) -Crv_vxl; + *(Crv_vybrk++) = (float) -Crv_vyl; + } + } + +/* Store extra information about the curve in the returned structure, and + purge any zero length sections. */ + if( cdata ){ + cdata->length = Crv_len; + cdata->out = Crv_out; + cdata->nbrk = Crv_nbrk; + PurgeCdata( cdata, status ); + } + +/* Annul the Frame and Mapping. */ + Map1_frame = astAnnul( Map1_frame ); + Map1_map = astAnnul( Map1_map ); + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, gridid, 0, GRF__LINE, method, class ); + + } + +/* Return. */ + return; + +} + +static void BBuf( AstPlot *this, int *status ) { +/* +*++ +* Name: +c astBBuf +f AST_BBUF + +* Purpose: +* Begin a new graphical buffering context. + +* Type: +* Public function. + +* Synopsis: +c #include "plot.h" +c void astBBuf( AstPlot *this ) +f CALL AST_BBUF( THIS STATUS ) + +* Class Membership: +* Plot member function. + +* Description: +c This function +f This routine +* starts a new graphics buffering context. A matching call to the +c function astEBuf +f routine AST_EBUF +* should be used to end the context. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +* - The nature of the buffering is determined by the underlying +* graphics system (as defined by the current grf module). Each call +c to this function +f to this routine +c to this function +f to this routine +* simply invokes the astGBBuf function in the grf module. + +*-- +*/ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Invoke the active GRF BBuf function. */ + GBBuf( this, "astBBuf", astGetClass( this ), status ); + +} + +static int Boundary( AstPlot *this, const char *method, const char *class, int *status ){ +/* +* Name: +* Boundary + +* Purpose: +* Draw a boundary around regions containing valid physical positions. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int Boundary( AstPlot *this, const char *method, const char *class, int *status ) + +* Class Membership: +* Plot method. + +* Description: +* This function draws a boundary around the regions of the plotting +* area which contain valid, unclipped, physical coordinates, but does +* not include the intersections with the edges of the plotting area. +* +* Broadly, the algorithm is as follows: An initial coarse grid is +* created covering the entire plotting area. This grid consists of a +* regular square matrix of points in graphics coordinates, and the +* corresponding physical coordinates. An array of flags is created, +* one for each grid cell, indicating if the boundary passes through the +* cell. This is assumed to be the case if the cell has a mix of good and +* bad corners (i.e corners which have good or bad physical coordinates). +* This assumption does not locate all boundary cells though, since if +* the boundary passes into and out of a cell throught the same edge, +* the corners of the cell will be either all good or all bad. But for +* the moment, we just concentrate on the ones found using this simple +* assumption. For each such cell, a finer grid is then created covering +* the cell, and the boundary is drawn through this fine grid using +* TraceBorder. TraceBorder returns a set of four flags indicating which +* edges of the cell were intersected by the boundary. A check is then +* made on any of the four neighbouring cells into which the curve +* passes. If any of these cells were not flagged as boundary cells using +* the simple assumption described earlier, then they are flagged now +* (with a different flag value). Once all the cells located using the +* simple assumption have been processed, any further cells flagged +* with the new flag value are also processed using TraceBorder in the +* same way. This process is repeated until no extra boundary cells are +* found. + +* Parameters: +* this +* Pointer to a Plot. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A flag indicating if any regions containing invalid physical +* coordinates were found within the plotting area. + +* Notes: +* - This function assumes the physical coordinate Frame is +* 2-dimensional, and it should not be used if this is not the case. +* - A value of zero is returned if an error has already occurred, or +* if this function should fail for any reason. + +*/ + +/* Local Variables: */ + AstFrame *bfrm; /* Pointer to base Plot Frame */ + AstFrame *cfrm; /* Pointer to current Plot Frame */ + AstMapping *map; /* Pointer to Plot mapping (graphics -> physical) */ + AstMapping *rmap; /* Pointer to Plot mapping (graphics -> physical) */ + AstRegion *breg; /* Region mapped into base Plot Frame */ + double blbnd[ 2 ]; /* Lower grid bounds in base frame */ + double bubnd[ 2 ]; /* Upper grid bounds in base frame */ + double dx; /* Plotting area width */ + double dy; /* Plotting area height */ + double power; /* Exponent in pow call */ + double rat; /* Ratio by which to reduce DIM */ + double tol; /* Fractional plotting tolerance */ + int dim; /* No. of points along each edge of coarse grid */ + int edges[ 4 ]; /* Flags indicating edges bisected by boundary */ + int rate_disabled; /* Was the astRate method initially disabled? */ + int ret; /* Any regions containing bad physical coords? */ + +/* Check global status. */ + if( !astOK ) return 0; + +/* Initialise the answer to indicate that no regions containing invalid + physical coordinates have been found. */ + ret = 0; + +/* Get the current Frame from the Plot. */ + cfrm = astGetFrame( this, AST__CURRENT ); + +/* If it is a region, we use a special method, if possible, to trace the + Region boundary. Otherwise, we use a grid tracing method that makes no + assumptions about the nature of the Mapping or Frame. */ + if( !DrawRegion( this, cfrm, method, class, status ) ) { + +/* Each basic element of the boundary drawn by the following algorithm + will be drawn at a multiple of 45 degrees to the horizontal. This can + cause noticable aliasing. For instance, if the border is a straight + line at 50 degrees to the horizontal, it will be drawn at 45 degrees + for long sections, followed by a vertical leap to catch up with where + it should be. Because of this we use a finer tolerance than for other + drawing. */ + tol = 0.25*astGetTol( this ); + +/* Set up the dimension of a coarse grid in graphics coordinates to cover the + whole plotting area. This is chosen to give a finer grid for smaller + plotting tolerances. Note, putting the power as a literal constant in + the call to pow seems to cause a segmentation violation on some systems. */ + power = -0.666666666; + dim = (int) 4*pow( tol, power ) + 10; + if( dim > 400 ) dim = 400; + if( dim < 3 ) dim = 3; + +/* Store the required plotting tolerance as a distance in graphics + coords. */ + dx = fabs( this->xhi - this->xlo ); + dy = fabs( this->xhi - this->xlo ); + tol *= ( ( dx > dy ) ? dx : dy ); + +/* Extract the Mapping from the Plot. */ + map = astGetMapping( this, AST__BASE, AST__CURRENT ); + +/* Select the area covered by the coarse grid. If the current Frame is a + Region, we use the bounding box of Region after being mapped into + graphics coords. */ + if( astIsARegion( cfrm ) ) { + bfrm = astGetFrame( this, AST__BASE ); + +/* Get the Mapping from the current to the base Frame in the Plot, and + remove the effects of any Regions. */ + + astInvert( map ); + rmap = astRemoveRegions( map ); + astInvert( map ); + +/* Map the Region into the GRAPHICS frame. */ + breg = astMapRegion( cfrm, rmap, bfrm ); + astGetRegionBounds( breg, blbnd, bubnd ); + + rmap = astAnnul( rmap ); + bfrm = astAnnul( bfrm ); + breg = astAnnul( breg ); + + rat = ( ( bubnd[ 0 ] - blbnd[ 0 ] )*( bubnd[ 1 ] - blbnd[ 1 ] ) )/ + ( ( this->xhi - this->xlo )*( this->yhi - this->ylo ) ); + rat = sqrt( rat ); + dim = (int) ( rat*dim ); + if( dim < 3 ) dim = 3; + +/* If the current Frame is not a Region, use the whole plot. */ + } else { + blbnd[ 0 ] = this->xlo; + blbnd[ 1 ] = this->ylo; + bubnd[ 0 ] = this->xhi; + bubnd[ 1 ] = this->yhi; + } + +/* Disable the astRate method in order to improve the speed of + evaluating the Mapping in cases where the Mapping includes an + AstRateMap. Note the original value of the flag so that it can be + re-instated at the end. */ + rate_disabled = astRateState( 1 ); + +/* Draw the boundary. */ + ret = TraceBorder( this, map, blbnd[ 0 ], bubnd[ 0 ], blbnd[ 1 ], + bubnd[ 1 ], dim, tol, edges, method, class, status ); + +/* Re-instate the original setting of the "astRate disabled" flag. */ + astRateState( rate_disabled ); + +/* Release the remaining resources. */ + map = astAnnul( map ); + } + cfrm = astAnnul( cfrm ); + +/* If an error has occurred, return 0. */ + if( !astOK ) ret = 0; + +/* Return the answer. */ + return ret; +} + +static int Border( AstPlot *this_nd, int *status ){ +/* +*++ +* Name: +c astBorder +f AST_BORDER + +* Purpose: +* Draw a border around valid regions of a Plot. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "plot.h" +c int astBorder( AstPlot *this ) +f RESULT = AST_BORDER( THIS, STATUS ) + +* Class Membership: +* Plot method. + +* Description: +* This function draws a (line) border around regions of the +* plotting area of a Plot which correspond to valid, unclipped +* physical coordinates. For example, when plotting using an +* all-sky map projection, this function could be used to draw the +* boundary of the celestial sphere when it is projected on to the +* plotting surface. +* +* If the entire plotting area contains valid, unclipped physical +* coordinates, then the boundary will just be a rectangular box +* around the edges of the plotting area. +* +* If the Plot is a Plot3D, this method is applied individually to +* each of the three 2D Plots encapsulated within the Plot3D (each of +* these Plots corresponds to a single 2D plane in the 3D graphics +* system). In addition, if the entire plotting volume has valid +* coordinates in the 3D current Frame of the Plot3D, then additional +* lines are drawn along the edges of the 3D plotting volume so that +* the entire plotting volume is enclosed within a cuboid grid. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Returned Value: +c astBorder() +f AST_BORDER = LOGICAL +c Zero is returned if the plotting space is completely filled by +f .FALSE. is returned if the plotting space is completely filled by +* valid, unclipped physical coordinates (so that only a +c rectangular box was drawn around the edge). Otherwise, one is +f rectangular box was drawn around the edge). Otherwise, .TRUE. is +* returned. + +* Notes: +c - A value of zero will be returned if this function is invoked +f - A value of .FALSE. will be returned if this function is invoked +c with the AST error status set, or if it should fail for any +f with STATUS set to an error value, or if it should fail for any +* reason. +* - An error results if either the current Frame or the base Frame +* of the Plot is not 2-dimensional or (for a Plot3D) 3-dimensional. +* - An error also results if the transformation between the base +* and current Frames of the Plot is not defined (i.e. the Plot's +* TranForward attribute is zero). +*-- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstPlot *this; /* Plot with no more than 2 current axes */ + AstPlotCurveData cdata; /* Structure to receive break information */ + const char *class; /* Object class */ + const char *method; /* Current method */ + int inval; /* Were any bad regions found? */ + int naxes; /* No. of axes in the base Frame */ + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this_nd); + +/* Store the current method, and the class of the supplied object for use + in error messages.*/ + method = "astBorder"; + class = astGetClass( this_nd ); + +/* Initialise the bounding box for primitives produced by this call. */ + if( !Boxp_freeze ) { + Boxp_lbnd[ 0 ] = FLT_MAX; + Boxp_lbnd[ 1 ] = FLT_MAX; + Boxp_ubnd[ 0 ] = FLT_MIN; + Boxp_ubnd[ 1 ] = FLT_MIN; + } + +/* Check the base Frame of the Plot is 2-D. */ + naxes = astGetNin( this_nd ); + if( naxes != 2 && astOK ){ + astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " + "Frame of the supplied %s is invalid - this number should " + "be 2.", status, method, class, naxes, class ); + } + +/* Get a Plot with a 2D (or 1D) current Frame. */ + this = (AstPlot *) Fset2D( (AstFrameSet *) this_nd, AST__CURRENT, status ); + +/* Check the current Frame of the Plot is 2-D. */ + naxes = astGetNout( this ); + if( naxes != 2 && astOK ){ + astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the current " + "Frame of the supplied %s is invalid - this number should " + "be 2.", status, method, class, naxes, class ); + } + +/* Indicate that the GRF module should re-calculate it's cached values + (in case the state of the graphics system has changed since the last + thing was drawn). */ + RESET_GRF; + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + astGrfAttrs( this, AST__BORDER_ID, 1, GRF__LINE, method, class ); + +/* We first draw the intersections of the regions containing valid + physical coordinates with the edges of the plotting area. First do + the bottom edge. */ + LinePlot( this, this->xlo, this->ylo, this->xhi, this->ylo, + 1, &cdata, method, class, status ); + +/* Now do the right-hand edge. */ + LinePlot( this, this->xhi, this->ylo, this->xhi, this->yhi, + 1, &cdata, method, class, status ); + +/* Now do the top edge. */ + LinePlot( this, this->xhi, this->yhi, this->xlo, this->yhi, + 1, &cdata, method, class, status ); + +/* Now do the left-hand edge. */ + LinePlot( this, this->xlo, this->yhi, this->xlo, this->ylo, + 1, &cdata, method, class, status ); + +/* Now draw a curve following the boundary through the interior of the + plotting area. If the current Frame in the Plot is a Region, we use a + shorter method if possible. If this is not possible, we use a longer + method. */ + inval = Boundary( this, method, class, status ); + +/* Ensure all lines are flushed to the graphics system. */ + Fpoly( this, method, class, status ); + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, AST__BORDER_ID, 0, GRF__LINE, method, class ); + +/* Annul the 2d plot. */ + this = astAnnul( this ); + +/* Return. */ + return inval; + +} + +static void BoundingBox( AstPlot *this, float lbnd[2], float ubnd[2], int *status ){ +/* +*++ +* Name: +c astBoundingBox +f AST_BOUNDINGBOX + +* Purpose: +* Return a bounding box for previously drawn graphics. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "plot.h" +c void astBoundingBox( AstPlot *this, float lbnd[2], float ubnd[2] ) +f CALL AST_BOUNDINGBOX( THIS, LBND, UBND, STATUS ) + +* Class Membership: +* Plot method. + +* Description: +c This function returns the bounds of a box which just encompasess the +f This routine returns the bounds of a box which just encompasess the +* graphics produced by the previous call to any of the Plot methods +* which produce graphical output. If no such previous call has yet +* been made, or if the call failed for any reason, then the bounding box +c returned by this function is undefined. +f returned by this routine is undefined. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +c lbnd +f LBND( 2 ) = REAL (Returned) +* A two element array in which is returned the lower limits of the +* bounding box on each of the two axes of the graphics coordinate +* system (the base Frame of the Plot). +c ubnd +f UBND( 2 ) = REAL (Returned) +* A two element array in which is returned the upper limits of the +* bounding box on each of the two axes of the graphics coordinate +* system (the base Frame of the Plot). +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +* - An error results if the base Frame of the Plot is not +* 2-dimensional. +*-- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstFrameSet *fset; /* Pointer to the Plot's FrameSet */ + int naxes; /* No. of axes in the base Frame */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Get a pointer to the FrameSet at the start of the Plot. */ + fset = (AstFrameSet *) this; + +/* Check the base Frame of the Plot is 2-D. */ + naxes = astGetNin( fset ); + if( naxes != 2 && astOK ){ + astError( AST__NAXIN, "astBoundingBox(%s): Number of axes (%d) in the " + "base Frame of the supplied %s is invalid - this number " + "should be 2.", status, astGetClass( this ), naxes, + astGetClass( this ) ); + } + +/* Return the bounding box. */ + lbnd[ 0 ] = Boxp_lbnd[ 0 ]; + lbnd[ 1 ] = Boxp_lbnd[ 1 ]; + ubnd[ 0 ] = Boxp_ubnd[ 0 ]; + ubnd[ 1 ] = Boxp_ubnd[ 1 ]; + +/* Return. */ + return; + +} + +static int BoxCheck( float *bx, float *by, float *cx, float *cy, int *status ) { +/* +* Name: +* BoxCheck + +* Purpose: +* See if two boxes overlap. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int BoxCheck( float *bx, float *by, float *cx, float *cy, int *status ) + +* Class Membership: +* Plot method. + +* Description: +* This function returns a flag indicating if two trapezoidal boxes +* (box "b" and box "c") overlap or not. + +* Parameters: +* bx +* Pointer to an array holding the X coordinates at the 4 corners +* of box "b". +* by +* Pointer to an array holding the Y coordinates at the 4 corners +* of box "b". +* cx +* Pointer to an array holding the X coordinates at the 4 corners +* of box "c". +* cy +* Pointer to an array holding the Y coordinates at the 4 corners +* of box "c". +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Zero is returned if the boxes do not overlap or an error has +* already occurred. Otherwise, 1 is returned. + +*/ + +/* Local Variables: */ + float x2; + float y2; + int i; + int ip; + int j; + int jp; + int ret; + +/* Assume the boxes do not overlap. */ + ret = 0; + +/* Check the inherited status. */ + if( !astOK ) return ret; + +/* Check each corner of box b to see if it is inside box c. */ + for( j = 0; j < 4 && ret == 0; j++ ){ + if( Inside( 4, cx, cy, bx[ j ], by[ j ], status ) ) ret = 1; + } + +/* Now check each corner of box c to see if it is inside box b. */ + for( j = 0; j < 4 && ret == 0; j++ ){ + if( Inside( 4, bx, by, cx[ j ], cy[ j ], status ) ) ret = 1; + } + +/* If no overlap has yet been found, we need to see if any of the edges + of the boxes intersect. For instance, in the case of a cross formed by + a vertical rectangle crossing a horizontal rectangle, the above checks + on the corners would not have revealed any overlap. */ + if( !ret ) { + +/* The following code assumes that the corners with indices 0, 1, 2, 3 + are adjacent round the edge of the box. This is the case if the line + joining corners 0 and 1 does not cross the line joining corners 2 and + 3 AND the line joining corners 1 and 2 does not cross the line joining + corners 3 and 0. If either of these conditions is not met swap the + corners around to correct it. First do box b. */ + if( Cross( bx[0], by[0], bx[1], by[1], + bx[2], by[2], bx[3], by[3], status ) ) { + x2 = bx[2]; + y2 = by[2]; + bx[2] = bx[1]; + by[2] = by[1]; + bx[1] = x2; + by[1] = y2; + + } else if( Cross( bx[1], by[1], bx[2], by[2], + bx[3], by[3], bx[0], by[0], status ) ) { + x2 = bx[2]; + y2 = by[2]; + bx[2] = bx[3]; + by[2] = by[3]; + bx[3] = x2; + by[3] = y2; + } + +/* Now do box c. */ + if( Cross( cx[0], cy[0], cx[1], cy[1], + cx[2], cy[2], cx[3], cy[3], status ) ) { + x2 = cx[2]; + y2 = cy[2]; + cx[2] = cx[1]; + cy[2] = cy[1]; + cx[1] = x2; + cy[1] = y2; + + } else if( Cross( cx[1], cy[1], cx[2], cy[2], + cx[3], cy[3], cx[0], cy[0], status ) ) { + x2 = cx[2]; + y2 = cy[2]; + cx[2] = cx[3]; + cy[2] = cy[3]; + cx[3] = x2; + cy[3] = y2; + } + +/* We now check each edge of box b to see if it overlaps any edge of box c. */ + for( j = 0; j < 4 && ret == 0; j++ ) { + +/* This edge of box b starts at the corner with index j. Get the index of the + corner at which the edge ends. */ + jp = j + 1; + if( jp == 4 ) jp = 0; + +/* Check to see if this edge of box b crosses each edge of box c in turn. */ + for( i = 0; i < 4 && ret == 0; i++ ) { + ip = i + 1; + if( ip == 4 ) ip = 0; + + ret = Cross( bx[j], by[j], bx[jp], by[jp], + cx[i], cy[i], cx[ip], cy[ip], status ); + + } + } + } + + return ret; +} + +static void Bpoly( AstPlot *this, float x, float y, int *status ){ +/* +* Name: +* Bpoly + +* Purpose: +* Begin a new poly line. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Bpoly( AstPlot *this, float x, float y, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function draws any current poly line, and then starts a new one +* at the supplied position. + +* Parameters: +* x +* The graphics x coordinate. +* y +* The graphics y coordinate. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + int ignore; /* Is the new point the end of the current polyline? */ + +/* Check the global status. */ + if( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* See if the new point is co-incident with the end of the current + polyline. If so we assume the current polyline is to be re-started, + rather than starting a new polyline. */ + if( Poly_n > 0 ) { + ignore = ( astEQUALS( Poly_x[ Poly_n - 1 ], x, 1.0E8 ) && + astEQUALS( Poly_y[ Poly_n - 1 ], y, 1.0E8 ) ); + } else { + ignore = 0; + } + +/* If the supplied point is not at the end of the current polyline, draw + any existing poly line. This will empty the buffer. Then add the + supplied point into the buffer. */ + if( !ignore ) { + Opoly( this, status ); + Apoly( this, x, y, status ); + } + +} + + +static int CGCapWrapper( AstPlot *this, int cap, int value, int *status ) { +/* +* +* Name: +* CGCapWrapper + +* Purpose: +* Call a C implementation of the GCap Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CGCapWrapper( AstPlot *this, int cap, int value, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* This function is a wrapper for a C implementation of the GCap +* grf function to enquire or set a graphics attribute value. + +* Parameters: +* this +* The Plot. +* cap +* The capability to be inquired aboue. +* value +* The value ot assign to the capability. +* status +* Pointer to the inherited status value. + +* Returned Value: +* Non-zero if the grf module is capabale of performing the action +* requested by "cap". + +*/ + if( !astOK ) return 0; + return ( (AstGCapFun) this->grffun[ AST__GCAP ] )( astGrfConID(this), cap, value ); +} + +static int CGAttrWrapper( AstPlot *this, int attr, double value, + double *old_value, int prim, int *status ) { +/* +* +* Name: +* CGAttrWrapper + +* Purpose: +* Call a C implementation of the GAttr Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CGAttrWrapper( AstPlot *this, int attr, double value, +* double *old_value, int prim, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* This function is a wrapper for a C implementation of the GAttr +* grf function to enquire or set a graphics attribute value. + +* Parameters: +* this +* The Plot. +* attr +* An integer value identifying the required attribute. The +* following symbolic values are defined in grf.h: +* +* GRF__STYLE - Line style. +* GRF__WIDTH - Line width. +* GRF__SIZE - Character and marker size scale factor. +* GRF__FONT - Character font. +* GRF__COLOUR - Colour index. +* value +* A new value to store for the attribute. If this is AST__BAD +* no value is stored. +* old_value +* A pointer to a double in which to return the attribute value. +* If this is NULL, no value is returned. +* prim +* The sort of graphics primitive to be drawn with the new attribute. +* Identified by the following values defined in grf.h: +* GRF__LINE +* GRF__MARK +* GRF__TEXT +* status +* Pointer to the inherited status value. + +*/ + if( !astOK ) return 0; + return ( (AstGAttrFun) this->grffun[ AST__GATTR ] )( astGrfConID(this), attr, value, old_value, prim ); +} + +static int CGBBufWrapper( AstPlot *this, int *status ) { +/* +* +* Name: +* CGBBufWrapper + +* Purpose: +* Call a C implementation of the GBBuf Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CGBBufWrapper( AstPlot *this ) { + +* Class Membership: +* Plot private function. + +* Description: +* This function is a wrapper for a C implementation of the GBBuf +* grf function to start a new graphics context. + +* Parameters: +* this +* The Plot. +* status +* Pointer to the inherited status value. + +*/ + if( !astOK ) return 0; + return ( (AstGBBufFun) this->grffun[ AST__GBBUF ])( astGrfConID(this) ); +} + +static int CGEBufWrapper( AstPlot *this, int *status ) { +/* +* +* Name: +* CGEBufWrapper + +* Purpose: +* Call a C implementation of the GEBuf Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CGEBufWrapper( AstPlot *this ) { + +* Class Membership: +* Plot private function. + +* Description: +* This function is a wrapper for a C implementation of the GEBuf +* grf function to start a new graphics context. + +* Parameters: +* this +* The Plot. +* status +* Pointer to the inherited status value. + +*/ + if( !astOK ) return 0; + return ( (AstGEBufFun) this->grffun[ AST__GEBUF ])( astGrfConID(this) ); +} + +static int CGFlushWrapper( AstPlot *this, int *status ) { +/* +* +* Name: +* CGFlushWrapper + +* Purpose: +* Call a C implementation of the GFlush Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CGFlushWrapper( AstPlot *this ) { + +* Class Membership: +* Plot private function. + +* Description: +* This function is a wrapper for a C implementation of the GFlush +* grf function to flush graphics. + +* Parameters: +* this +* The Plot. +* status +* Pointer to the inherited status value. + +*/ + if( !astOK ) return 0; + return ( (AstGFlushFun) this->grffun[ AST__GFLUSH ])( astGrfConID(this) ); +} + +static int CGLineWrapper( AstPlot *this, int n, const float *x, + const float *y, int *status ) { +/* +* +* Name: +* CGLineWrapper + +* Purpose: +* Call a C implementation of the GLine Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CGLineWrapper( AstPlot *this, int n, const float *x, +* const float *y, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* This function is a wrapper for a C implementation of the GLine +* grf function to draw a polyline. + +* Parameters: +* this +* The Plot. +* n +* The number of positions to be joined together. +* x +* A pointer to an array holding the "n" x values. +* y +* A pointer to an array holding the "n" y values. +* status +* Pointer to the inherited status variable. + +*/ + if( !astOK ) return 0; + return ( (AstGLineFun) this->grffun[ AST__GLINE ])( astGrfConID(this), n, x, y ); +} + +static int CGMarkWrapper( AstPlot *this, int n, const float *x, + const float *y, int type, int *status ) { +/* +* +* Name: +* CGMarkWrapper + +* Purpose: +* Call a C implementation of the GMark Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CGMarkWrapper( AstPlot *this, int n, const float *x, +* const float *y, int type, int *status ) { + +* Class Membership: +* Plot private function. + +* Description: +* This function is a wrapper for a C implementation of the GMark grf +* function to draw markers. + +* Parameters: +* this +* The Plot. +* n +* The number of positions to be joined together. +* x +* A pointer to an array holding the "n" x values. +* y +* A pointer to an array holding the "n" y values. +* type +* An integer which can be used to indicate the type of marker symbol +* required. +* status +* Pointer to the inherited status value. + +*/ + if( !astOK ) return 0; + return ( (AstGMarkFun) this->grffun[ AST__GMARK ])( astGrfConID(this), n, x, y, type ); +} + +static int CGTextWrapper( AstPlot *this, const char *text, float x, float y, + const char *just, float upx, float upy, int *status ) { +/* +* +* Name: +* CGTextWrapper + +* Purpose: +* Call a C implementation of the GText Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CGTextWrapper( AstPlot *this, const char *text, float x, float y, +* const char *just, float upx, float upy, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* This function is a wrapper for a C implementation of the GText grf +* function to draw a text string. + +* Parameters: +* this +* The Plot. +* text +* Pointer to a null-terminated character string to be displayed. +* x +* The reference x coordinate. +* y +* The reference y coordinate. +* just +* A character string which specifies the location within the +* text string which is to be placed at the reference position +* given by x and y. The first character may be 'T' for "top", +* 'C' for "centre", or 'B' for "bottom", and specifies the +* vertical location of the reference position. Note, "bottom" +* corresponds to the base-line of normal text. Some characters +* (eg "y", "g", "p", etc) descend below the base-line. The second +* character may be 'L' for "left", 'C' for "centre", or 'R' +* for "right", and specifies the horizontal location of the +* reference position. If the string has less than 2 characters +* then 'C' is used for the missing characters. +* upx +* The x component of the up-vector for the text, in graphics world +* coordinates. If necessary the supplied value should be negated +* to ensure that positive values always refer to displacements from +* left to right on the screen. +* upy +* The y component of the up-vector for the text, in graphics world +* coordinates. If necessary the supplied value should be negated +* to ensure that positive values always refer to displacements from +* bottom to top on the screen. +* status +* Pointer to the inherited status value. + +*/ + if( !astOK ) return 0; + return ( (AstGTextFun) this->grffun[ AST__GTEXT ])( astGrfConID(this), text, x, y, just, upx, upy ); +} + +static int CGTxExtWrapper( AstPlot *this, const char *text, float x, float y, + const char *just, float upx, float upy, float *xb, + float *yb, int *status ) { +/* +* +* Name: +* CGTxExtWrapper + +* Purpose: +* Call a C implementation of the GTxExt Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CGTxExtWrapper( AstPlot *this, const char *text, float x, float y, +* const char *just, float upx, float upy, float *xb, +* float *yb, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* This function is a wrapper for a C implementation of the GTxExt +* grf function to find the extent of a text string. + +* Parameters: +* this +* The Plot. +* text +* Pointer to a null-terminated character string to be displayed. +* x +* The reference x coordinate. +* y +* The reference y coordinate. +* just +* A character string which specifies the location within the +* text string which is to be placed at the reference position +* given by x and y. The first character may be 'T' for "top", +* 'C' for "centre", or 'B' for "bottom", and specifies the +* vertical location of the reference position. Note, "bottom" +* corresponds to the base-line of normal text. Some characters +* (eg "y", "g", "p", etc) descend below the base-line. The second +* character may be 'L' for "left", 'C' for "centre", or 'R' +* for "right", and specifies the horizontal location of the +* reference position. If the string has less than 2 characters +* then 'C' is used for the missing characters. +* upx +* The x component of the up-vector for the text, in graphics world +* coordinates. If necessary the supplied value should be negated +* to ensure that positive values always refer to displacements from +* left to right on the screen. +* upy +* The y component of the up-vector for the text, in graphics world +* coordinates. If necessary the supplied value should be negated +* to ensure that positive values always refer to displacements from +* bottom to top on the screen. +* xb +* An array of 4 elements in which to return the x coordinate of +* each corner of the bounding box. +* yb +* An array of 4 elements in which to return the y coordinate of +* each corner of the bounding box. +* status +* Pointer to the inherited status variable. + +*/ + if( !astOK ) return 0; + return ( (AstGTxExtFun) this->grffun[ AST__GTXEXT ])( astGrfConID(this), text, x, y, just, upx, upy, xb, yb ); +} + +static int CGQchWrapper( AstPlot *this, float *chv, float *chh, int *status ) { +/* +* +* Name: +* CGQchWrapper + +* Purpose: +* Call a C implementation of the GQch Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CGQchWrapper( AstPlot *this, float *chv, float *chh, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* This function is a wrapper for a C implementation of the GQch +* grf function to find the extent of a text string. + +* Parameters: +* this +* The Plot. +* chv +* A pointer to the double which is to receive the height of +* characters drawn vertically. This will be an increment in the X +* axis +* chh +* A pointer to the double which is to receive the height of +* characters drawn vertically. This will be an increment in the Y +* axis +* status +* Pointer to the inherited status value. +*/ + if( !astOK ) return 0; + return ( (AstGQchFun) this->grffun[ AST__GQCH ])( astGrfConID(this), chv, chh ); +} + +static int CGScalesWrapper( AstPlot *this, float *alpha, float *beta, int *status ) { +/* +* +* Name: +* CGScalesWrapper + +* Purpose: +* Call a C implementation of the GScales Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CGScalesWrapper( AstPlot *this, float *alpha, float *beta, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* This function is a wrapper for a C implementation of the GScales +* grf function to find the extent of a text string. + +* Parameters: +* this +* The Plot. +* alpha +* A pointer to the location at which to return the scale for the +* X axis (i.e. Xnorm = alpha*Xworld). +* beta +* A pointer to the location at which to return the scale for the +* Y axis (i.e. Ynorm = beta*Yworld). +* status +* Pointer to the inherited status value. +*/ + if( !astOK ) return 0; + return ( (AstGScalesFun) this->grffun[ AST__GSCALES ])( astGrfConID(this), alpha, beta ); +} + +static int CheckLabels( AstPlot *this, AstFrame *frame, int axis, + double *ticks, int nticks, int force, char **list, + double refval, int *status ){ +/* +* Name: +* CheckLabels + +* Purpose: +* Create tick mark labels and check that adjacent labels are different. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CheckLabels( AstPlot *this, AstFrame *frame, int axis, double *ticks, +* int nticks, int force, char **list, double refval, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function formats the supplied ticks mark values using the +* astFormat method for the supplied Frame. Unless force is non-zero, it +* then checks all pairs of adjacent labels. If a pair is found which are +* identical then the memory holding the labels is released, and a value +* of zero is returned. Otherwise, a value of one is returned, indicating +* that adjacent labels are all different and the labels are returned. + +* Parameters: +* this +* Pointer to the Plot. +* frame +* Pointer to the Frame. +* axis +* The zero-based index of the axis to which the tick marks refer. +* ticks +* Pointer to an array holding the tick mark values. +* nticks +* The number of tick marks supplied by parameter "ticks". +* force +* If non-zero, then no check for identical adjacent labels is +* performed, and the labels are always considered to be OK. +* list +* Pointer to the start of an array of pointers. Each of the +* elements in this array receives a pointer to a string holding a +* formatted label. Each of these strings should be freed using +* astFree when no longer needed. +* refval +* A value to use for the other axis when normalizing. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Zero if any pairs of identical adjacent labels were found. One +* otherwise. + +* Notes: +* - No error is reported if a pair of identical adjacent labels is +* found. +* - If an error has already occurred, or if this function should +* fail for any reason, a value of zero is returned, and the array of +* pointers identified by "list" is filled with NULL pointers. + + +*/ + +/* Local Variables: */ + const char *label; /* Pointer to formatted tick value */ + double val[ 2 ]; /* Workspace for normalizing */ + int i; /* Tick index */ + int len; /* Number of characters in curent label */ + int ok; /* The returned flag */ + +/* Fill the supplied label list with NULL pointers. */ + if( list ) { + for( i = 0; i < nticks; i++ ) list[ i ] = NULL; + } + +/* Check the global status. */ + if( !astOK ) return 0; + +/* Initialise the returned flag to indicate that all adjacent labels are + different. */ + ok = 1; + +/* Normalize and format the first tick mark value. */ + val[ axis ] = ticks[ 0 ]; + val[ 1 - axis ] = refval; + astNorm( frame, val ); + label = astFormat( frame, axis, val[ axis ] ); + +/* Allocate memory holding a copy of the formatted value, and store a + pointer to this copy in the list of labels. */ + if( label ){ + len = strlen( label ) + 1; + list[ 0 ] = (char *) astStore( NULL, (void *) label, len ); + } else { + ok = 0; + } + +/* Normalize and format each of the tick mark values in this batch. */ + for( i = 1; i < nticks && astOK && ok; i++ ){ + val[ axis ] = ticks[ i ]; + val[ 1 - axis ] = refval; + astNorm( frame, val ); + label = astFormat( frame, axis, val[ axis ] ); + if( label ){ + +/* Unless checks have been supressed, compare this label with the previous + label. If they are identical clear the returned flag. */ + if( !force && !strcmp( label, list[ i - 1 ] ) ) { + ok = 0; + +/* Allocate memory holding a copy of the label, and store a + pointer to this copy in the list of labels. */ + } else { + list[ i ] = (char *) astStore( NULL, (void *) label, strlen( label ) + 1 ); + } + + } else { + ok = 0; + } + + } + +/* If two adjacent labels were identical, or an error occurred, release the + memory used to store the labels. */ + if( !ok || !astOK ){ + for( i = 0; i < nticks; i++ ){ + if( list[ i ] ) list[ i ] = (char *) astFree( (void *) list[ i ] ); + } + } + +/* Ensure a value of zero is returned if an error has occurred. */ + if( !astOK ) ok = 0; + +/* Return the answer. */ + return ok; + +} + +static char **CheckLabels2( AstPlot *this, AstFrame *frame, int axis, + double *ticks, int nticks, char **old_list, + double refval, int *status ){ +/* +* Name: +* CheckLabels2 + +* Purpose: +* Check that labels cannot be shortened. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* char **CheckLabels2( AstPlot *this, AstFrame *frame, int axis, +* double *ticks, int nticks, char **old_list, +* double refval, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function formats the supplied ticks mark values using the +* astFormat method for the supplied Frame. It then compares the labels +* with the corresponding labels supplied in "old_list". If all of the +* new labels are shorter than, or equal in length to, the old labels, +* then memory is allocated to hold the new (shorter) labels, and a +* pointer to this memory is returned. If any new label is longer than +* the corresponding old label, then a NULL pointer is returned. +* +* No check is performed on whether or not there are any identical +* adjacent labels. + +* Parameters: +* this +* Pointer to the Plot. +* frame +* Pointer to the Frame. +* axis +* The zero-based index of the axis to which the tick marks refer. +* ticks +* Pointer to an array holding the tick mark values. +* nticks +* The number of tick marks supplied by parameter "ticks". +* old_list +* Pointer to the start of an array of pointers. Each of the +* elements in this array should hold a pointer to a string holding a +* formatted label. +* refval +* A value to use for the other axis when normalizing. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to an array of pointers. Each of these pointers points to +* a text string holding a shortened label. If a complete set of +* shortened labels could not be found (or if an error occurs), a NULL +* pointer is returned. + +* Notes: +* - The memory holding the returned shortened labels should be +* freed by cthe caller, together with the memory holding the pointers to +* the labels. +* - No error is reported if a pair of identical adjacent labels is +* found. +* - If an error has already occurred, or if this function should +* fail for any reason, a value of NULL is returned. + +*/ + +/* Local Variables: */ + char **list; /* The returned pointer */ + const char *label; /* Pointer to formatted tick value */ + double val[ 2 ]; /* Workspace for normalizing */ + int i; /* Tick index */ + int llen; /* Number of characters in curent label */ + int ok; /* Are the old labels OK to be used? */ + +/* Check the global status. */ + if( !astOK ) return NULL; + +/* Allocate memory to hold the pointers to the new labels. */ + list = (char **) astMalloc( sizeof( char * )*(size_t) nticks ); + if( list ) { + +/* Fill this array with NULLs for safety. */ + for( i = 0; i < nticks; i++ ) list[ i ] = NULL; + +/* Initialise a flag to indicate that all the new labels are + shorter than the old labels. */ + ok = 0; + +/* Normalize and format each of the tick mark values in this batch. */ + for( i = 0; i < nticks && astOK; i++ ){ + val[ axis ] = ticks[ i ]; + val[ 1 - axis ] = refval; + astNorm( frame, val ); + label = astFormat( frame, axis, val[ axis ] ); + if( label ){ + +/* Get the length of the new label. */ + llen = strlen( label ); + +/* Compare this label with the corresponding old label. If the new one is + longer than the old one, set the flag and leave the loop. */ + if( llen > strlen( old_list[ i ] ) ) { + ok = 1; + break; + } + +/* Store the new label. */ + list[ i ] = (char *) astStore( NULL, (void *) label, + (size_t) (llen + 1) ); + } + } + +/* If the old labels are to be used, or an error occurred, release the memory + used to store the new labels. */ + if( ok || !astOK ){ + for( i = 0; i < nticks; i++ ){ + if( list[ i ] ) list[ i ] = (char *) astFree( (void *) list[ i ] ); + } + list = (char **) astFree( (void *) list ); + } + + } + +/* Return the answer. */ + return list; + +} + +static int ChrLen( const char *string, int *status ){ +/* +* Name: +* ChrLen + +* Purpose: +* Return the length of a string excluding any trailing white space. + +* Type: +* Private function. + +* Synopsis: +* int ChrLen( const char *string, int *status ) + +* Class Membership: +* Plot + +* Description: +* This function returns the length of a string excluding any trailing +* white space. + +* Parameters: +* string +* Pointer to the string. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The length of a string excluding any trailing white space. + +* Notes: +* - A value of zero is returned if a NULL pointer is supplied, or if an +* error has already occurred. + +*/ + +/* Local Variables: */ + const char *c; /* Pointer to the next character to check */ + int ret; /* The returned string length */ + +/* Check the global status. */ + if( !astOK ) return 0; + +/* Initialise the returned string length. */ + ret = 0; + +/* Check a string has been supplied. */ + if( string ){ + +/* Check each character in turn, starting with the last one. */ + ret = strlen( string ); + c = string + ret - 1; + while( ret ){ + if( !isspace( (int) *c ) ) break; + c--; + ret--; + } + } + +/* Return the answer. */ + return ret; + +} + +static AstPlotCurveData **CleanCdata( AstPlotCurveData **cdata, int *status ){ +/* +* Name: +* CleanCdata + +* Purpose: +* Release the structures holding curve break information. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* AstPlotCurveData **CleanCdata( AstPlotCurveData **cdata, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function releases the memory used to hold the curve break +* information returned by function DrawGrid, and returns a NULL pointer. + +* Parameters: +* cdata +* Pointer to the information to be freed. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A NULL pointer. + +* Notes: +* - This function attempts to execute even if an error has already +* occurred. + +*/ + +/* Return if a NULL pointer has been supplied. */ + if( !cdata ) return NULL; + +/* Release each of the two structures in turn (if they exist). */ + (void) astFree( (void *) cdata[ 0 ] ); + (void) astFree( (void *) cdata[ 1 ] ); + +/* Release the memory used to hold the two AstPlotCurveData pointers. */ + (void) astFree( (void *) cdata ); + +/* Return. */ + return NULL; + +} + +static TickInfo **CleanGrid( TickInfo **grid, int *status ){ +/* +* Name: +* CleanGrid + +* Purpose: +* Release the structures holding grid information. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* TickInfo **CleanGrid( TickInfo **grid ) + +* Class Membership: +* Plot member function. + +* Description: +* This function releases the memory used to hold the grid information +* returned by function GridLines, and returns a NULL pointer. + +* Parameters: +* grid +* Pointer to the information to be freed. + +* Returned Value: +* A NULL pointer. + +* Notes: +* - This function attempts to execute even if an error has already +* occurred. + +*/ + +/* Local Variables: */ + TickInfo *info; /* Pointer to TickInfo structure being freed */ + int i; /* Axis index */ + int j; /* Tick mark index */ + +/* Return if a NULL pointer has been supplied. */ + if( !grid ) return NULL; + +/* Release each of the TickInfo structures in turn (if they exist). */ + for( i = 0; i < 2; i++ ){ + if( ( info = grid[ i ] ) ){ + +/* Release the memory holding major tick mark values. */ + (void) astFree( (void *) info->ticks ); + +/* Release the memory holding minor tick mark values. */ + (void) astFree( (void *) info->minticks ); + +/* Release the memory holding curve section starting positions. */ + (void) astFree( (void *) info->start ); + +/* Release the memory holding curve section lengths. */ + (void) astFree( (void *) info->length ); + +/* If there are any tick mark labels in the structure... */ + if( info->labels ){ + +/* Release the memory holding each tick mark label. */ + for( j = 0; j < info->nmajor; j++ ){ + (void) astFree( (void *) info->labels[ j ] ); + } + +/* Release the memory holding the pointers to the tick mark labels. */ + (void) astFree( (void *) info->labels ); + +/* Release the memory holding the format specification string. */ + (void) astFree( (void *) info->fmt ); + + } + +/* Release the TickInfo structure. */ + (void) astFree( (void *) info ); + } + } + +/* Release the memory used to hold the two TickInfo pointers. */ + (void) astFree( (void *) grid ); + +/* Return. */ + return NULL; + +} + +static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { +/* +* Name: +* ClearAttrib + +* Purpose: +* Clear an attribute value for a Plot. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void ClearAttrib( AstObject *this, const char *attrib, int *status ) + +* Class Membership: +* Plot member function (over-rides the astClearAttrib protected +* method inherited from the FrameSet class). + +* Description: +* This function clears the value of a specified attribute for a +* Plot, so that the default value will subsequently be used. + +* Parameters: +* this +* Pointer to the Plot. +* attrib +* Pointer to a null terminated string specifying the attribute +* name. This should be in lower case with no surrounding white +* space. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + AstPlot *this; /* Pointer to the Plot structure */ + char label[21]; /* Graphics item label */ + const char *class; /* Pointer to class string */ + int axis; /* Axis number */ + int id1; /* Plot object id */ + int id2; /* Plot object id */ + int id; /* Plot object id */ + int len; /* Length of attrib string */ + int nax; /* Number of base Frame axes */ + int nc; /* No. characters read by astSscanf */ + int id3; /* Third genuine identifier */ + int nid; /* Number of genuine attributes */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the Plot structure. */ + this = (AstPlot *) this_object; + +/* Get the number of base Frame axis (2 for a Plot, 3 for a Plot3D). */ + nax = astGetNin( this ); + +/* Obtain the length of the "attrib" string. */ + len = strlen( attrib ); + +/* Check the attribute name and clear the appropriate attribute. */ + +/* Edge(axis). */ +/* ------------ */ + if ( nc = 0, + ( 1 == astSscanf( attrib, "edge(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearEdge( this, axis - 1 ); + +/* Grid. */ +/* ----- */ + } else if ( !strcmp( attrib, "grid" ) ) { + astClearGrid( this ); + +/* LabelUp */ +/* ------- */ + } else if ( !strcmp( attrib, "labelup" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearLabelUp( this, axis ); + +/* LabelUp(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "labelup(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearLabelUp( this, axis - 1 ); + +/* LogPlot */ +/* ------- */ + } else if ( !strcmp( attrib, "logplot" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearLogPlot( this, axis ); + +/* LogPlot(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "logplot(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearLogPlot( this, axis - 1 ); + +/* LogTicks */ +/* ------- */ + } else if ( !strcmp( attrib, "logticks" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearLogTicks( this, axis ); + +/* LogTicks(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "logticks(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearLogTicks( this, axis - 1 ); + +/* LogLabel */ +/* ------- */ + } else if ( !strcmp( attrib, "loglabel" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearLogLabel( this, axis ); + +/* LogLabel(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "loglabel(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearLogLabel( this, axis - 1 ); + +/* NumLab. */ +/* ---------- */ + } else if ( !strcmp( attrib, "numlab" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearNumLab( this, axis ); + +/* NumLab(axis). */ +/* ---------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "numlab(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearNumLab( this, axis - 1 ); + +/* MinTick. */ +/* ---------- */ + } else if ( !strcmp( attrib, "mintick" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearMinTick( this, axis ); + +/* MinTick(axis). */ +/* ---------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "mintick(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearMinTick( this, axis - 1 ); + +/* TextLab. */ +/* ---------- */ + } else if ( !strcmp( attrib, "textlab" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearTextLab( this, axis ); + +/* TextLab(axis). */ +/* --------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "textlab(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearTextLab( this, axis - 1 ); + +/* LabelUnits. */ +/* --------- */ + } else if ( !strcmp( attrib, "labelunits" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearLabelUnits( this, axis ); + +/* LabelUnits(axis). */ +/* --------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "labelunits(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearLabelUnits( this, axis - 1 ); + +/* Style. */ +/* ------ */ + } else if ( !strcmp( attrib, "style" ) ) { + for( id = 0; id < AST__NPID; id++ ) astClearStyle( this, id ); + +/* Style(label). */ +/* --------------*/ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "style(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + class = astGetClass( this ); + + nid = IdFind( FullForm( GrfLabels, label, attrib, "astClear", class, status ), + nax, &id1, &id2, &id3, status ); + astClearStyle( this, id1 ); + if( nid > 1 ) astClearStyle( this, id2 ); + if( nid > 2 ) astClearStyle( this, id3 ); + +/* Font. */ +/* ----- */ + } else if ( !strcmp( attrib, "font" ) ) { + for( id = 0; id < AST__NPID; id++ ) astClearFont( this, id ); + +/* Font(label). */ +/* -------------*/ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "font(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + class = astGetClass( this ); + + nid = IdFind( FullForm( GrfLabels, label, attrib, "astClear", class, status ), + nax, &id1, &id2, &id3, status ); + astClearFont( this, id1 ); + if( nid > 1 ) astClearFont( this, id2 ); + if( nid > 2 ) astClearFont( this, id3 ); + +/* Colour. */ +/* ------- */ + } else if ( !strcmp( attrib, "colour" ) ) { + for( id = 0; id < AST__NPID; id++ ) astClearColour( this, id ); + +/* Colour(label). */ +/* ---------------*/ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "colour(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + class = astGetClass( this ); + + nid = IdFind( FullForm( GrfLabels, label, attrib, "astClear", class, status ), + nax, &id1, &id2, &id3, status ); + astClearColour( this, id1 ); + if( nid > 1 ) astClearColour( this, id2 ); + if( nid > 2 ) astClearColour( this, id3 ); + +/* Color. */ +/* ------ */ + } else if ( !strcmp( attrib, "color" ) ) { + for( id = 0; id < AST__NPID; id++ ) astClearColour( this, id ); + +/* Color(label). */ +/* --------------*/ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "color(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + class = astGetClass( this ); + + nid = IdFind( FullForm( GrfLabels, label, attrib, "astClear", class, status ), + nax, &id1, &id2, &id3, status ); + astClearColour( this, id1 ); + if( nid > 1 ) astClearColour( this, id2 ); + if( nid > 2 ) astClearColour( this, id3 ); + +/* Width. */ +/* ------ */ + } else if ( !strcmp( attrib, "width" ) ) { + for( id = 0; id < AST__NPID; id++ ) astClearWidth( this, id ); + +/* Width(label). */ +/* --------------*/ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "width(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + class = astGetClass( this ); + + nid = IdFind( FullForm( GrfLabels, label, attrib, "astClear", class, status ), + nax, &id1, &id2, &id3, status ); + + astClearWidth( this, id1 ); + if( nid > 1 ) astClearWidth( this, id2 ); + if( nid > 2 ) astClearWidth( this, id3 ); + +/* Size. */ +/* ----- */ + } else if ( !strcmp( attrib, "size" ) ) { + for( id = 0; id < AST__NPID; id++ ) astClearSize( this, id ); + +/* Size(label). */ +/* -------------*/ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "size(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + class = astGetClass( this ); + + nid = IdFind( FullForm( GrfLabels, label, attrib, "astClear", class, status ), + nax, &id1, &id2, &id3, status ); + astClearSize( this, id1 ); + if( nid > 1 ) astClearSize( this, id2 ); + if( nid > 2 ) astClearSize( this, id3 ); + +/* LabelAt(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "labelat(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearLabelAt( this, axis - 1 ); + +/* Centre(axis). */ +/* ------------ */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "centre(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearCentre( this, axis - 1 ); + +/* Gap. */ +/* ---- */ + } else if ( !strcmp( attrib, "gap" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearGap( this, axis ); + +/* Gap(axis). */ +/* ---------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "gap(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearGap( this, axis - 1 ); + +/* LogGap. */ +/* ----------- */ + } else if ( !strcmp( attrib, "loggap" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearLogGap( this, axis ); + +/* LogGap(axis). */ +/* ----------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "loggap(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearLogGap( this, axis - 1 ); + +/* NumLabGap. */ +/* ---------- */ + } else if ( !strcmp( attrib, "numlabgap" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearNumLabGap( this, axis ); + +/* NumLabGap(axis). */ +/* ---------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "numlabgap(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearNumLabGap( this, axis - 1 ); + +/* TextLabGap. */ +/* ----------- */ + } else if ( !strcmp( attrib, "textlabgap" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearTextLabGap( this, axis ); + +/* TextLabGap(axis). */ +/* ----------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "textlabgap(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearTextLabGap( this, axis - 1 ); + +/* TitleGap. */ +/* --------- */ + } else if ( !strcmp( attrib, "titlegap" ) ) { + astClearTitleGap( this ); + +/* MajTickLen. */ +/* ----------- */ + } else if ( !strcmp( attrib, "majticklen" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearMajTickLen( this, axis ); + +/* MajTickLen(axis). */ +/* ----------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "majticklen(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearMajTickLen( this, axis - 1 ); + +/* MinTickLen. */ +/* ----------- */ + } else if ( !strcmp( attrib, "minticklen" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearMinTickLen( this, axis ); + +/* MinTickLen(axis). */ +/* ----------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "minticklen(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearMinTickLen( this, axis - 1 ); + +/* Labelling. */ +/* -------- */ + } else if ( !strcmp( attrib, "labelling" ) ) { + astClearLabelling( this ); + +/* TickAll. */ +/* -------- */ + } else if ( !strcmp( attrib, "tickall" ) ) { + astClearTickAll( this ); + +/* ForceExterior */ +/* ------------- */ + } else if ( !strcmp( attrib, "forceexterior" ) ) { + astClearForceExterior( this ); + +/* Invisible. */ +/* ---------- */ + } else if ( !strcmp( attrib, "invisible" ) ) { + astClearInvisible( this ); + +/* Border. */ +/* ------- */ + } else if ( !strcmp( attrib, "border" ) ) { + astClearBorder( this ); + +/* ClipOp. */ +/* ------- */ + } else if ( !strcmp( attrib, "clipop" ) ) { + astClearClipOp( this ); + +/* Clip. */ +/* ----- */ + } else if ( !strcmp( attrib, "clip" ) ) { + astClearClip( this ); + +/* Grf. */ +/* ---- */ + } else if ( !strcmp( attrib, "grf" ) ) { + astClearGrf( this ); + +/* DrawTitle. */ +/* ---------- */ + } else if ( !strcmp( attrib, "drawtitle" ) ) { + astClearDrawTitle( this ); + +/* DrawAxes. */ +/* --------- */ + } else if ( !strcmp( attrib, "drawaxes" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearDrawAxes( this, axis ); + +/* Abbrev */ +/* ------ */ + } else if ( !strcmp( attrib, "abbrev" ) ) { + for( axis = 0; axis < nax; axis++ ) astClearAbbrev( this, axis ); + +/* DrawAxes(axis). */ +/* --------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "drawaxes(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearDrawAxes( this, axis - 1 ); + +/* Abbrev(axis). */ +/* ------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "abbrev(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + astClearAbbrev( this, axis - 1 ); + +/* Escape. */ +/* ------- */ + } else if ( !strcmp( attrib, "escape" ) ) { + astClearEscape( this ); + +/* Tol. */ +/* ---- */ + } else if ( !strcmp( attrib, "tol" ) ) { + astClearTol( this ); + +/* If the attribute is still not recognised, pass it on to the parent + method for further interpretation. */ + } else { + (*parent_clearattrib)( this_object, attrib, status ); + } +} + +static void ClearLogPlot( AstPlot *this, int axis, int *status ){ +/* +* +* Name: +* ClearLogPlot + +* Purpose: +* Clear the value for a LogPlot attribute + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void ClearLogPlot( AstPlot *this, int axis, int *status ) + +* Class Membership: +* Plot member function + +* Description: +* Assigns the default value to the LogPlot attribute of the specified +* axis, and also re-maps the base Frame of the Plot if necessary. + +* Parameters: +* this +* The Plot. +* axis +* Zero based axis index. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + int oldval; /* Original value of the attribute */ + int newval; /* Cleared (default) value of the attribute */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Validate the axis index. */ + if( axis < 0 || axis >= 2 ){ + astError( AST__AXIIN, "astClearLogPlot(%s): Index (%d) is invalid for " + "attribute LogPlot - it should be in the range 1 to 2.", status, + astGetClass( this ), axis + 1 ); + +/* Do nothing if the attribute is not currently set. */ + } else if( astTestLogPlot( this, axis ) ){ + +/* Get the original value of the attribute. clear the value, and then get + the new (default) value. */ + oldval = this->logplot[ axis ]; + this->logplot[ axis ] = -1; + newval = astGetLogPlot( this, axis ); + +/* If the effective value has changed, attempt to remap the axis. If this + fails, re-instate the original value. */ + if( ( oldval != 0 ) != ( newval != 0 ) ) { + if( !ToggleLogLin( this, axis, oldval, "astClearLogPlot", status ) ) { + this->logplot[ axis ] = oldval; + } + } + } +} + +static void Clip( AstPlot *this, int iframe, const double lbnd[], + const double ubnd[], int *status ){ +/* +*++ +* Name: +c astClip +f AST_CLIP + +* Purpose: +* Set up or remove clipping for a Plot. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "plot.h" +c void astClip( AstPlot *this, int iframe, const double lbnd[], +c const double ubnd[] ) +f CALL AST_CLIP( THIS, IFRAME, LBND, UBND, STATUS ) + +* Class Membership: +* Plot method. + +* Description: +c This function defines regions of a Plot which are to be clipped. +f This routine defines regions of a Plot which are to be clipped. +* Any subsequent graphical output created using the Plot will then +* be visible only within the unclipped regions of the plotting +* area. See also the Clip attribute. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +c iframe +f IFRAME = INTEGER (Given) +* The index of the Frame within the Plot to which the clipping +c limits supplied in "lbnd" and "ubnd" (below) refer. Clipping +f limits supplied in LBND and UBND (below) refer. Clipping +* may be applied to any of the coordinate systems associated +* with a Plot (as defined by the Frames it contains), so this +* index may take any value from 1 to the number of Frames in +* the Plot (Nframe attribute). In addition, the values +* AST__BASE and AST__CURRENT may be used to specify the base +* and current Frames respectively. +* +* For example, a value of AST__CURRENT causes clipping to be +* performed in physical coordinates, while a value of AST__BASE +* would clip in graphical coordinates. Clipping may also be +* removed completely by giving a value of AST__NOFRAME. In this +* case any clipping bounds supplied (below) are ignored. +c lbnd +f LBND( * ) = DOUBLE PRECISION (Given) +* An array with one element for each axis of the clipping Frame +c (identified by the index "iframe"). This should contain the +f (identified by the index IFRAME). This should contain the +* lower bound, on each axis, of the region which is to remain +* visible (unclipped). +c ubnd +f UBND( * ) = DOUBLE PRECISION (Given) +* An array with one element for each axis of the clipping Frame +c (identified by the index "iframe"). This should contain the +f (identified by the index IFRAME). This should contain the +* upper bound, on each axis, of the region which is to remain +* visible (unclipped). +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +c - Only one clipping Frame may be active at a time. This function +f - Only one clipping Frame may be active at a time. This routine +* will deactivate any previously-established clipping Frame before +* setting up new clipping limits. +c - The clipping produced by this function is in addition to that +f - The clipping produced by this routine is in addition to that +* specified by the Clip attribute which occurs at the edges of the +* plotting area +c established when the Plot is created (see astPlot). The +f established when the Plot is created (see AST_PLOT). The +* underlying graphics system may also impose further clipping. +* - When testing a graphical position for clipping, it is first +* transformed into the clipping Frame. The resulting coordinate on +* each axis is then checked against the clipping limits (given by +c "lbnd" and "ubnd"). By default, a position is clipped if any +f LBND and UBND). By default, a position is clipped if any +* coordinate lies outside these limits. However, if a non-zero +* value is assigned to the Plot's ClipOp attribute, then a +* position is only clipped if the coordinates on all axes lie +* outside their clipping limits. +* - If the lower clipping limit exceeds the upper limit for any +* axis, then the sense of clipping for that axis is reversed (so +* that coordinate values lying between the limits are clipped +* instead of those lying outside the limits). To produce a "hole" +* in a coordinate space (that is, an internal region where nothing +* is plotted), you should supply all the bounds in reversed order, +* and set the ClipOp attribute for the Plot to a non-zero value. +* - Either clipping limit may be set to the value AST__BAD, which +* is equivalent to setting it to infinity (or minus infinity for a +* lower bound) so that it is not used. +* - If a graphical position results in any bad coordinate values +* (AST__BAD) when transformed into the clipping Frame, then it is +* treated (for the purposes of producing graphical output) as if +* it were clipped. +* - When a Plot is used as a Mapping to transform points +c (e.g. using astTran2), any clipped output points are assigned +f (e.g. using AST_TRAN2), any clipped output points are assigned +* coordinate values of AST__BAD. +* - An error results if the base Frame of the Plot is not +* 2-dimensional. +*-- +*/ + +/* Local Variables: */ + AstFrame *fr; /* Pointer to the clipping Frame */ + AstFrameSet *fset; /* Pointer to the Plot's FrameSet */ + int i; /* Axis index */ + int ifrm; /* The validated frame index */ + int naxes; /* No. of axes in the base Frame */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + ifrm = 0; + +/* Get a pointer to the FrameSet at the start of the Plot. */ + fset = (AstFrameSet *) this; + +/* Check the base Frame of the Plot is 2-D. */ + naxes = astGetNin( fset ); + if( naxes != 2 && astOK ){ + astError( AST__NAXIN, "astClip(%s): Number of axes (%d) in the " + "base Frame of the supplied %s is invalid - this number " + "should be 2.", status, astGetClass( this ), naxes, + astGetClass( this ) ); + } + +/* If clipping is to be switched on, check the supplied frame index and + bounds. */ + if( iframe != AST__NOFRAME && astOK ) { + +/* Report an error if either of the bounds pointers is NULL.*/ + if( !lbnd ){ + astError( AST__CLPAX, "astClip(%s): A NULL pointer was " + "supplied for the array holding the lower bounds of " + "the clipping volume.", status, astGetClass( this ) ); + } else if( !ubnd ){ + astError( AST__CLPAX, "astClip(%s): A NULL pointer was " + "supplied for the array holding the upper bounds of " + "the clipping volume.", status, astGetClass( this ) ); + } + +/* Validate the clipping frame index. */ + ifrm = astValidateFrameIndex( fset, iframe, "astClip" ); + +/* Get the number of axes in the clipping frame. */ + fr = astGetFrame( this, ifrm ); + naxes = astGetNaxes( fr ); + fr = astAnnul( fr ); + + } + +/* Leave the current clipping information unchanged if an error has + occurred. */ + if( astOK ){ + +/* Remove all clipping information from the Plot. */ + this->clip_lbnd = (double *) astFree( (void *) this->clip_lbnd ); + this->clip_ubnd = (double *) astFree( (void *) this->clip_ubnd ); + this->clip_frame = AST__NOFRAME; + this->clip_axes = 0; + +/* If bounds have been supplied, set up new clipping information. */ + if( iframe != AST__NOFRAME ){ + +/* Store the information. */ + this->clip_frame = ifrm; + this->clip_lbnd = astStore( NULL, lbnd, sizeof(double)*(size_t)naxes ); + this->clip_ubnd = astStore( NULL, ubnd, sizeof(double)*(size_t)naxes ); + this->clip_axes = naxes; + +/* If an error has occurred, remove all clipping information. */ + if( !astOK ){ + this->clip_lbnd = (double *) astFree( (void *) this->clip_lbnd ); + this->clip_ubnd = (double *) astFree( (void *) this->clip_ubnd ); + this->clip_frame = AST__NOFRAME; + this->clip_axes = 0; + +/* Otherwise, replace any bounds of AST__BAD with suitable default + values. */ + } else { + for( i = 0; i < naxes; i++ ){ + if( this->clip_lbnd[ i ] == AST__BAD ) this->clip_lbnd[ i ] = -DBL_MAX; + if( this->clip_ubnd[ i ] == AST__BAD ) this->clip_ubnd[ i ] = DBL_MAX; + } + + } + + } + + } + +/* Return. */ + return; + +} + +static int Compared( const void *elem1, const void *elem2 ){ +/* +* Name: +* Compared + +* Purpose: +* Compare two "double" values. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int Compared( const void *elem1, const void *elem2 ) + +* Class Membership: +* Plot method. + +* Description: +* This function compares the two "double" values to which pointers +* are supplied, and returns an integer indicating which is larger, +* checking for AST__BAD values. It is intended for use with the C +* Run-Time-Library sorting function "qsort". + +* Parameters: +* elem1 +* Pointer to the first "double". +* elem2 +* Pointer to the second "double". + +* Returned Value: +* Zero is returned if the values are equal. If the first is larger +* than the second then +1 is returned. Otherwise, -1 is returned. + +* Notes: +* - Values of AST__BAD are considered to be larger than any other +* value (other than another value of AST__BAD). +* - If both values are AST__BAD, then zero is returned. +* - This function executes even if an error has occurred. + +*/ + +/* Local Variables: */ + double *delem1; /* Pointer to the first "double" value */ + double *delem2; /* Pointer to the second "double" value */ + int ret; /* The returned value */ + +/* Get pointers to the two "double" values. */ + delem1 = (double *) elem1; + delem2 = (double *) elem2; + +/* Check the values for equality (including both values being AST__BAD). */ + if( *delem1 == *delem2 ){ + ret = 0; + +/* If the first is bad, then it is considered to be larger than the + second. */ + } else if( *delem1 == AST__BAD ){ + ret = 1; + +/* If the second is bad, then it is considered to be larger than the + first. */ + } else if( *delem2 == AST__BAD ){ + ret = -1; + +/* If the first is larger than the second, return 1. */ + } else if( *delem1 > *delem2 ){ + ret = 1; + +/* If the first is smaller than the second, return -1. */ + } else { + ret = -1; + + } + +/* Return the answer. */ + return ret; + +} + +static int Compare_LL( const void *elem1, const void *elem2 ){ +/* +* Name: +* Compare_LL + +* Purpose: +* Compare two LabelList structures as used by function PlotLabels. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int Compare_LL( const void *elem1, const void *elem2 ) + +* Class Membership: +* Plot method. + +* Description: +* This function compares two "LabelList" structures as used by function +* PlotLabels, and returns an integer indicating which has a larger +* "index" value. This function is intended to be used with the C +* Run-Time-Library sorting function "qsort". + +* Parameters: +* elem1 +* Pointer to the first LabelList. +* elem2 +* Pointer to the second LabelList. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Zero is returned if the values are equal. If the first is larger +* than the second then +1 is returned. Otherwise, -1 is returned. + +* Notes: +* - This function executes even if an error has occurred. + +*/ + +/* Local Variables: */ + LabelList *ll1; /* Pointer to the first LabelList */ + LabelList *ll2; /* Pointer to the second LabelList */ + int ret; /* The returned value */ + +/* Get pointers to the two LabelList structures. */ + ll1 = (LabelList *) elem1; + ll2 = (LabelList *) elem2; + +/* Compare the indices for the two label's. */ + if( ll1->index < ll2->index ){ + ret = -1; + + } else if( ll1->index > ll2->index ){ + ret = 1; + + } else { + ret = 0; + } + +/* Return the answer. */ + return ret; + +} + +static void CopyPlotDefaults( AstPlot *this, int axis, AstPlot *dplot, + int daxis, int *status ){ +/* +*+ +* Name: +* astCopyPlotDefaults + +* Purpose: +* Copy used attribute defaults from one Plot to another. + +* Type: +* Protected virtual function. + +* Synopsis: +* #include "plot.h" +* void astCopyPlotDefaults( AstPlot *this, int axis, AstPlot *dplot, +* int daxis ) + +* Class Membership: +* Plot method. + +* Description: +* Some of the attributes used by the Plot class have dynamic default +* values that are determined during the process of drawing an annotated +* grid using astGrid. The dynamic default values are stored in a +* separate set of components within the Plot structure. This function +* copies these components from one Plot to another. + +* Parameters: +* this +* Pointer to a Plot containing the values ot be copied. +* axis +* The zero-based index of the axis within "this" for which the +* used defaults are to be copied. +* dplot +* A pointer to another Plot into which the default attribute +* values are to be copied. +* daxis +* The zero based index of the axis within "dplot" which is to +* receive the new values. + +*- +*/ + +/* Check the global status. */ + if( !astOK ) return; + + dplot->ulglb[ daxis ] = this->ulglb[ axis ]; + dplot->ulgtk[ daxis ] = this->ulgtk[ axis ]; + dplot->uloggap[ daxis ] = this->uloggap[ axis ]; + dplot->ugap[ daxis ] = this->ugap[ axis ]; + dplot->ucentre[ daxis ] = this->ucentre[ axis ]; + dplot->uedge[ daxis ] = this->uedge[ axis ]; + dplot->ulblat[ daxis ] = this->ulblat[ axis ]; + dplot->ulbunit[ daxis ] = this->ulbunit[ axis ]; + dplot->umintk[ daxis ] = this->umintk[ axis ]; + dplot->utxtlb[ daxis ] = this->utxtlb[ axis ]; + dplot->umjtkln[ daxis ] = this->umjtkln[ axis ]; + + dplot->ugrid = this->ugrid; + dplot->ulbling = this->ulbling; + dplot->uborder = this->uborder; +} + +static int CountGood( int n, double *data, int *status ){ +/* +* Name: +* CountGood + +* Purpose: +* Coount the number of non-bad values in an array. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int CountGood( int n, double *data, int *status ) + +* Class Membership: +* Plot method. + +* Description: +* This function returns the number of elements in the supplied array +* which do not have the value AST__BAD. + +* Parameters: +* n +* The total number of elements in the array. +* data +* Pointer to the start of the array. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The number of good points in the array. + +* Notes: +* - A value of zero is returned if an error has already occurred. + +*/ + +/* Local Variables: */ + int i; + int ngood; + double *value; + +/* Check global status. */ + if( !astOK ) return 0; + +/* Initialise a pointer to the next array element, and the number of + good elements found so far. */ + value = data; + ngood = 0; + +/* Check each element. */ + for( i = 0; i < n; i++ ){ + if( *(value++) != AST__BAD ) ngood++; + } + +/* Return the answer. */ + return ngood; + +} + +static int Cross( float ax, float ay, float bx, float by, + float cx, float cy, float dx, float dy, int *status ){ +/* +* Name: +* Cross + +* Purpose: +* See if two line segments intersect. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int Cross( float ax, float ay, float bx, float by, +* float cx, float cy, float dx, float dy, int *status ) + +* Class Membership: +* Plot method. + +* Description: +* This function sees if the line segment (A,B) intersects the line +* segment (C,D). + +* Parameters: +* ax, ay +* The coordinates of A. +* bx, by +* The coordinates of B. +* cx, cy +* The coordinates of C. +* dx, dy +* The coordinates of D. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Zero if the line segments do not cross or if an error has already +* occurred, and 1 if they do. + +*/ + +/* Local Variables: */ + int ret; + float m1, m2, denom, num, t1, t2; + +/* Check the inherited status. */ + if( !astOK ) return 0; + +/* Get the fraction of the distance from A to B at which the line AB + intersects the line CD. */ + m1 = dx - cx; + m2 = dy - cy; + denom = (bx - ax)*m2 - (by-ay)*m1; + num = (ay - cy)*m1 - (ax - cx)*m2; + + if( denom != 0.0 ) { + t1 = num / denom; + +/* If the the intersection occurs within the segment of the line between A + and B... */ + if( t1 >= 0.0 && t1 <= 1.0 ){ + +/* ... then get the fraction of the distance from C to D at which the + line CD intersects the line AB. */ + m1 = bx - ax; + m2 = by - ay; + denom = (dx - cx)*m2 - (dy-cy)*m1; + num = (cy - ay)*m1 - (cx - ax)*m2; + + if( denom != 0.0 ) { + t2 = num / denom; + +/* If the the intersection occurs within the segment of the line between C + and D then the line segments intersect. */ + if( t2 >= 0.0 && t2 <= 1.0 ){ + ret = 1; + } else { + ret = 0; + } + +/* If the two lines are parallel, then they do not intersect. */ + } else { + ret = 0; + } + + } else { + ret = 0; + } + + } else { + ret = 0; + + } + + return ret; +} + +static void Crv( AstPlot *this, double *d, double *x, double *y, int skipbad, + double *box, CrvStatics *pstatics, const char *method, + const char *class, int *status ){ +/* +* Name: +* Crv + +* Purpose: +* Draw a curve. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Crv( AstPlot *this, double *d, double *x, double *y, int skipbad, +* double *box, CrvStatics *pstatics, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function draws a curve parameterised by the distance from some +* starting point. The function pointed to by the external variable +* Crv_map is used to transform distances along the curve into graphics +* coordinates (X,Y). The supplied function parameters defined the +* section of the curve to be drawn. +* +* The algorithm used needs no knowledge about the nature of the mapping +* performed by Crv_map, and can handle discontinuities in the curve. It +* first of all determines if any of the segments of the curve can be +* adequately represented by simply drawing a straight line through the +* supplied end points. This decision is based on several requirements such +* as keeping the angle between adjacent sections low and both ends being +* defined (i.e. X and Y not equal to AST__BAD). Any segments of the curve +* which satisfy the requirements are draw as straight lines. If any of +* the supplied curve segments cannot be drawn in this way, then they are +* split up into a set of evenly-spaced sub-segments and the graphics +* coordinates at the ends of these sub-segments are found using Crv_map. +* This function is then called recursively to draw the sub-segments. This +* recursion is limited in depth by the requirement that all the +* sub-segments must be longer than a specified lower limit. If this is not +* the case, then the curve is assumed to be dis-continuous and and the +* sub-segments are ignored. + +* Parameters: +* d +* Pointer to an array of CRV_NPNT values giving the distance along +* the curve from the starting point to each of CRV_NPNT points. They +* should increase monotonically, and should be in whatever units are +* used by the function pointed to by Crv_map. The curve is drawn from +* d[0] to d[CRV_NPNT]. +* x +* Pointer to an array of CRV_NPNT values giving the graphics X +* coordinate for the positions supplied in the array pointed to by +* parameter "d". +* y +* Pointer to an array of CRV_NPNT values giving the graphics Y +* coordinate for the positions supplied in the array pointed to by +* parameter "d". +* skipbad +* Controls what happens if all the supplied points are bad or +* outside the plotting area. If skipbad is non-zero, then it is +* assumed that the supplied points represent an entirely bad (or +* out of bounds) section of the curve, and this function will +* return without attempt to sub-divide any of the supplied points. +* If skipbad is zero, then it is assumed that we may be able to find +* some good points between the supplied bad points, and therefore +* this function will attempt to sub-divide the supplied points. +* Should be supplied as zero on the initial invocation. +* box +* Pointer to an array of 4 doubles houlding a bounding box within +* which the current segment must reside if it is to be sub-divided. +* Supplied in the order xlo, xhi, ylo, yhi. May be NULL in which +* case, no check is made on the bounding box. +* pstatics +* Pointer to a structure holding values for variables which were +* statically defined within this function prior to the thread-safe +* version of AST. If a NULL pointer is supplied, a new structure +* is created in dynamic memory and initialised. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* External Variables: +* Crv_nent = int (Read/Write) +* The number of recursive entries which have been made into +* this function. This should be set to zero before entering +* this function for the first time. +* Crv_ux0 = double (Read/Write) +* The X component in graphics coordinates of the unit vector +* along the previous segment of the curve. This should be set +* to AST__BAD initially to indicate that the previous section +* is not defined. +* Crv_uy0 = double (Read/Write) +* The Y component of the unit vector along the previous segment. +* Crv_limit = double (Read) +* The square of the maximum acceptable residual between the +* drawn curve and the true curve, in graphics coordinates. +* Crv_scerr = double (Read) +* If the ratio of the lengths of adjacent sub-segments is larger +* than Crv_scerr,then the seub-segments will be sub-divided. Note, +* if either axis is mapped logarithmically onto the screen, then +* there will naturally be large changes in scale. Crv_scerr should +* always be larger than 1.0. +* Crv_map = void (*)( int n, double *dd, double *xx, double *yy, +* const char *method, const char *class ) (Read) +* A pointer to a function which can be called to map "n" distances +* along the curve (supplied in "dd") into graphics coordinates +* (stored in "xx" and "yy"). See function "Map1" as an example. +* Crv_clip = int (Read) +* Should lines be clipped at the edge of the plotting area? + +* Notes: +* - The CRV_TRACE conditional compilation blocks in this function +* provide code which displays the recursive entries made to this +* function (and also pauses on initial entry until return is pressed). +* It is useful for investigating the details of the drawing of a +* curve. + +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + CrvStatics *statics; /* Pointer to structure holding static values */ + double *dd; /* Pointer to array holding sub-segment distances */ + double *pd; /* Pointer to next sub-segment distance */ + double *px; /* Pointer to next sub-segment x coord. */ + double *py; /* Pointer to next sub-segment y coord. */ + double *xx; /* Pointer to array holding sub-segment x coord.s */ + double *yy; /* Pointer to array holding sub-segment x coord.s */ + double bbox[4]; /* Bounding box for this segment */ + double dl2[ CRV_NSEG ];/* Squred segment lengths */ + double dx[ CRV_NSEG ]; /* X increment along each segment */ + double dy[ CRV_NSEG ]; /* Y increment along each segment */ + int i; /* Segment index */ + int seg_ok[ CRV_NSEG ];/* Flags indicating which segments can be drawn */ + int subdivide; /* Flag indicating if segments can be subdivided */ + +/* Check inherited status */ + if( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* If required, allocate memory for a structure to hold the static + variables need by this function. */ + if( ! pstatics ) { + statics = astMalloc( sizeof( CrvStatics ) ); + } else { + statics = pstatics; + } + +/* If this is the first entry, set up the minimum length for a + sub-segment in graphics coordinates. If any segment is less than + this minimum length, then recursion will stop and the curve will + be assumed to be dis-continuous. */ + if( !Crv_nent ) { + statics->limit2 = 20.0*Crv_limit/(CRV_NSEG*CRV_NSEG); + +#ifdef CRV_TRACE + statics->levels[ 0 ] = 0; +#endif + } + + +/* Increment the number of entries into this function. */ + Crv_nent++; + +#ifdef CRV_TRACE + for( i = 0; i < Crv_nent; i++ ) { + printf("%d ",statics->levels[ i ] ); + } + printf("\n"); + + if( getchar() == 'm' ) { + float ffx,ffy; + for( i = 0; i < CRV_NPNT; i++ ) { + ffx = x[i]; ffy = y[i]; + GMark( this, 1, &ffx, &ffy, 2, method, class, status ); + GFlush( this, method, class, status ); + } + } +#endif + +/* ====================================================================== + The first section of this function sets up some arrays holding + information which will be used later on. It looks at each of the segments + joing adjacent tabulated points, and finds and stores the increments in + X and Y along each segment, and the square of the segment length. It + also checks to see if the tabulated points are all bad, or if they are + all good. It also finds the lowest squared segment length. + ======================================================================*/ + +/* Look at the first tabulated point. If it is good, set a flag to indicate + that it can be used, store it as "the previous position" (i.e. the start of + the current segment). Also set a flag ("all_bad") to indicate if all + points looked at so far have been bad, or outside the plotting area. */ + if( *x != AST__BAD && *y != AST__BAD ){ + statics->last_ok = 1; + statics->last_x = *x; + statics->last_y = *y; + statics->all_bad = ( *x < Crv_xlo || *x > Crv_xhi || + *y < Crv_ylo || *y > Crv_yhi ) && Crv_clip; + } else { + statics->last_ok = 0; + statics->all_bad = 1; + } + +/* Initialise the bouding box for the this segment. */ + bbox[ 0 ] = DBL_MAX; + bbox[ 1 ] = -DBL_MAX; + bbox[ 2 ] = DBL_MAX; + bbox[ 3 ] = -DBL_MAX; + +/* Store pointers to the X and Y values for the "current position". This + is the position at the end of the current segment. This is initially + the second tabulated point. */ + px = x + 1; + py = y + 1; + +/* Store pointers to the increments and squared length for the current + segment. */ + statics->pdx = dx; + statics->pdy = dy; + statics->pdl2 = dl2; + +/* Initialise the number of long and short segments. */ + statics->nlong = 0; + statics->nshort = 0; + +/* Loop round each segment. */ + for( i = 0; i < CRV_NSEG; i++ ){ + +/* If the tabulated point marking the end of the segment is good... */ + if( *px != AST__BAD && *py != AST__BAD ){ + +/* Update the bounding box. */ + if( *px < bbox[ 0 ] ) bbox[ 0 ] = *px; + if( *px > bbox[ 1 ] ) bbox[ 1 ] = *px; + if( *py < bbox[ 2 ] ) bbox[ 2 ] = *py; + if( *py > bbox[ 3 ] ) bbox[ 3 ] = *py; + +/* If the point is within the plotting area, set the "statics->all_bad" flag to + indicate that at least 1 point is within the plotting area. */ + if( !Crv_clip || ( *px >= Crv_xlo && *px <= Crv_xhi && + *py >= Crv_ylo && *py <= Crv_yhi ) ) statics->all_bad = 0; + +/* If the point marking the start of the segment was also good, find and + store the increments and squared length for the segment, incrementing + the pointers ready for the next segment. */ + if( statics->last_ok ){ + statics->t1 = *px - statics->last_x; + statics->t2 = *py - statics->last_y; + statics->t3 = statics->t1*statics->t1 + statics->t2*statics->t2; + *(statics->pdx++) = statics->t1; + *(statics->pdy++) = statics->t2; + *(statics->pdl2++) = statics->t3; + +/* Count the number of segments which are, and are not, shorter than the + minimum significant length. */ + if( statics->t3 > statics->limit2 ) { + statics->nlong++; + } else { + statics->nshort++; + } + +/* If the start was bad, the length of the segment is not defined so store + bad values. */ + } else { + *(statics->pdx++) = AST__BAD; + *(statics->pdy++) = AST__BAD; + *(statics->pdl2++) = AST__BAD; + } + +/* The point at the end of the current segment becomes the point at the + start of the next segment. */ + statics->last_ok = 1; + statics->last_x = *(px++); + statics->last_y = *(py++); + +/* If the tabulated point marking the end of the current segment is bad, + the segment length is undefined so store bad values. */ + } else { + *(statics->pdx++) = AST__BAD; + *(statics->pdy++) = AST__BAD; + *(statics->pdl2++) = AST__BAD; + +/* The point at the end of the current segment becomes the point at the + start of the next segment. */ + statics->last_ok = 0; + px++; + py++; + } + } + +/* ====================================================================== + The next section of this function checks to see lines can be drawn + directly through any of the tabulated points. The flags in "seg_ok" + indicates if this is the case for each segment. + ======================================================================*/ + +/* The unit vector along the previous segment is supplied in external + variables Crv_ux0 and Crv_uy0. These will be AST__BAD if the direction + of the previous segment is undefined. */ + statics->vxl = Crv_ux0; + statics->vyl = Crv_uy0; + +/* The length of the previous segment is initially bad. */ + statics->dll = AST__BAD; + +/* Set up some pointers used to walk through the arrays holding the lengths + of each segment. */ + statics->pdl2 = dl2; + statics->pdx = dx; + statics->pdy = dy; + +/* Check each segment in turn to see if it can be drawn as a single + straight line. */ + for( i = 0; i < CRV_NSEG; i++ ){ + +/* A segment can only be drawn as a single line if both ends are good + and the distance between them is not zero. */ + if( *statics->pdl2 != AST__BAD && *statics->pdl2 > 0.0 ){ + +/* Get a unit vector in the direction of the current segment. */ + statics->dl = sqrt( *statics->pdl2 ); + statics->vx = *statics->pdx/statics->dl; + statics->vy = *statics->pdy/statics->dl; + +/* If a unit vector in the direction of the previous segment is available, + we check that the angle between the previous segment and the current + segment is not too high. */ + if( statics->vxl != AST__BAD ){ + statics->cosang = statics->vxl*statics->vx + statics->vyl*statics->vy; + +/* If the angle is too high, set a flag to indicate that the segment cannot + be drawn as a single line. Also, set the flag for the previous segment as + well. */ + if( statics->cosang < 0.8 || + ( *statics->pdl2 )*( 1.0 - statics->cosang*statics->cosang ) > Crv_limit ) { + seg_ok[ i ] = 0; + if( i > 0 ) seg_ok[ i - 1 ] = 0; + + +/* If the angle between this segment and the previous segment is not too + high, check that the scale has not changed too much. */ + } else { + +/* If the scale (=vector length) has changed a lot, set a flag to indicate + that the segment cannot be drawn as a single line. Also, set the flag for + the previous segment as well. */ + if( statics->dll != AST__BAD && ( statics->dl < statics->dll/Crv_scerr || statics->dl > statics->dll*Crv_scerr ) ) { + seg_ok[ i ] = 0; + if( i > 0 ) seg_ok[ i - 1 ] = 0; + +/* If the orientation and scale of this segment has not changed much from + the previous segment, the segment can be drawn as a straight line. */ + } else { + seg_ok[ i ] = 1; + } + } + +/* If no unit vector is available for the previous segment, then assume + we are re-starting the curve after a discontinuity. In this case, we + can draw it as a straight line. */ + } else { + seg_ok[ i ] = 1; + } + +/* Save the unit vector along the current segment for use next time. */ + statics->vxl = statics->vx; + statics->vyl = statics->vy; + +/* Save the length if the current segment for use next time. */ + statics->dll = statics->dl; + +/* If the length of the current segment is undefined, or zero, we cannot + draw it as a single line. Also, there is no direction vector to pass + on to the next time, so set them bad. */ + } else { + seg_ok[ i ] = 0; + statics->vxl = AST__BAD; + statics->vyl = AST__BAD; + statics->dll = AST__BAD; + } + +/* Point to the next segment. */ + statics->pdl2++; + statics->pdx++; + statics->pdy++; + + } + +/* Do not allow isolated segments to be OK. If a segment is flagged as being + OK, but both its neighbours are not OK, set the segment not OK as well. */ + statics->seg0 = seg_ok + 1; + statics->segm = seg_ok; + statics->segp = seg_ok + 2; + + if( !(*statics->seg0) ) *statics->segm = 0; + + for( i = 1; i < CRV_NSEG - 1; i++ ){ + if( !(*statics->segm) && !(*statics->segp) ) *statics->seg0 = 0; + statics->seg0++; + statics->segm++; + statics->segp++; + } + + if( !(*statics->segm) ) *statics->seg0 = 0; + +/* ====================================================================== + The next section of this function draws the curve. Each segment is drawn + as a straight line if the corresponding flag in "seg_ok" is set. + Segments for which the flag is not set are drawn by calling this function + recursivly. + ======================================================================*/ + +/* Get the parametric length (i.e. the increment in "d") of the sub-segments + within each subdivided segment. */ + statics->delta = ( d[ CRV_NSEG ] - d[ 0 ] )/(double)( CRV_NSEG*CRV_NSEG ); + +/* If we have made the maximum number of recursive entries into this + function, or if every supplied point was bad or outside the plotting + area, or if most of the segments were very short in graphics space, we will + not be attempting to subdivide any segments which cannot be drawn directly + as a straight line. If "skipbad" was supplied as zero, we ignore the + restriction which says that we must have some good points (since we + may find some good poits by a further sub-division). */ + subdivide = ( Crv_nent < CRV_MXENT && + ( !statics->all_bad || !skipbad ) && + statics->nlong > statics->nshort ); + +/* We do not sub-divide if the bounding box of the supplied points + is not at least 10% smaller than the supplied bouding box on either axis. */ + if( box && bbox[ 0 ] != DBL_MAX ) { + if( bbox[ 1 ] - bbox[ 0 ] > 0.9*( box[ 1 ] - box[ 0 ] ) && + bbox[ 3 ] - bbox[ 2 ] > 0.9*( box[ 3 ] - box[ 2 ] ) ) { + subdivide = 0; + } + } + +/* Initialise some pointers to the data defineding the subsegments. */ + dd = NULL; + xx = NULL; + yy = NULL; + +/* If we may be subdividing any segments, find which segments they are + and set up the offset to each sub-segment. */ + if( subdivide ){ + +/* Initialise the number of segments being subdivided. */ + statics->nseg = 0; + +/* Loop round each segment. */ + for( i = 0; i < CRV_NSEG; i++ ){ + +/* If the segment cannot be drawn directly as a straight line, we will + subdivide it. */ + if( !seg_ok[ i ] ){ + +/* Increment the number of segments being subdivided, and let the array + of subsegment offsets grow to accomodate it. */ + statics->nseg++; + dd = (double *) astGrow( dd, statics->nseg, sizeof(double)*( CRV_NSEG + 1 ) ); + if( !astOK ) break; + +/* Append the offset to each new subsegment to the "dd" array. */ + statics->el = ( statics->nseg - 1 )*( CRV_NSEG + 1 ); + statics->d0 = d[ i ]; + for( statics->j = 0; statics->j <= CRV_NSEG; statics->j++ ){ + dd[ statics->el++ ] = statics->d0; + statics->d0 += statics->delta; + } + } + } + +/* If any segments needed subdividing, get room to store the graphics + coordinates at each point, and then fill these arrays by calling + Crv_map to map the offsets in "dd" into graphics coordinates. */ + if( statics->nseg > 0 ){ + statics->nel = statics->nseg*( CRV_NSEG + 1 ); + xx = (double *) astMalloc( sizeof(double)*(size_t)statics->nel ); + yy = (double *) astMalloc( sizeof(double)*(size_t)statics->nel ); + Crv_map( statics->nel, dd, xx, yy, method, class, status GLOBALS_NAME ); + } + } + +/* If all has gone OK, we will draw each segment. Initialise pointers + used to walk through the "xx", "yy" and "dd" arrays. */ + if( astOK ){ + px = xx; + py = yy; + pd = dd; + +/* Draw each segment in turn. */ + for( i = 0; i < CRV_NSEG; i++ ){ + +/* If possible, draw it as a single straight line, and then store the + unit vector along the line in the appropriate external variables for + use by the next invocation of this function. */ + if( seg_ok[ i ] ){ + CrvLine( this, x[ i ], y[ i ], x[ i + 1 ], y[ i + 1 ], method, class, status ); + statics->dl = sqrt( dl2[ i ] ); + Crv_ux0 = dx[ i ]/statics->dl; + Crv_uy0 = dy[ i ]/statics->dl; + +/* Otherwise, if we are subdividing, and if the current segment is + not very short, we call this function recursively to draw the segment. + Increment pointers into the "xx", "yy" and "dd" arrays so that they + point to the start of the subsegment information for the next segment + to be subdivided. If all the graphics positions at this level were + bad or outside the plot, tell the next invocation of Crv to do no + further sub-divisions if it too finds all graphics positions to be bad or + outside the plot. */ + } else if( subdivide ) { + +#ifdef CRV_TRACE + statics->levels[ Crv_nent ] = i; +#endif + + Crv( this, pd, px, py, statics->all_bad, bbox, statics, method, + class, status ); + pd += CRV_NSEG + 1; + px += CRV_NSEG + 1; + py += CRV_NSEG + 1; + +/* Otherwise, we assume we have hit a discontinuity in the curve. Store + bad values for the unit vector along the previous sgment, and do not + draw anything. */ + } else { + Crv_ux0 = AST__BAD; + Crv_uy0 = AST__BAD; + } + } + } + +/* Free any memory used to store subsegment information. */ + if( dd ) dd = (double *) astFree( (void *) dd ); + if( xx ) xx = (double *) astFree( (void *) xx ); + if( yy ) yy = (double *) astFree( (void *) yy ); + +/* Decrement the number of recursive entries into this function. */ + Crv_nent--; + +/* Free the memory holding the static data values if we are leaving the + final entry. */ + if( ! pstatics ) statics = astFree( statics ); + +/* Return. */ + return; +} + +static int CvBrk( AstPlot *this, int ibrk, double *brk, double *vbrk, + double *len, int *status ){ +/* +*+ +* Name: +* astCvBrk + +* Purpose: +* Return information about breaks in the last curve drawn by astGridLine, +* astCurve or astGenCurve. + +* Type: +* Protected virtual function. + +* Synopsis: +* #include "plot.h" +* int CvBrk( AstPlot *this, int ibrk, double *brk, double *vbrk, +* double *len ) + +* Class Membership: +* Plot method. + +* Description: +* Curves drawn by astGridLine, astCurve or astGenCurve may contain breaks +* for several reasons (for instance, it may go outside the plotting area, +* or the mapping between physical and graphics coordinates may be +* discontinuous). This function returns information about such breaks. + +* Parameters: +* this +* Pointer to a Plot. +* ibrk +* The index of the break for which information is required. The first +* break has index 1. An error is reported if no break with the +* required index exists. The exception to this is that zero can be +* supplied, in which case the "brk" and "vbrk" parameters +* are ignored, but all other information is returned. +* brk +* A pointer to an array of 2 elements +* in which to return the X and Y graphics coordinates of the break. +* vbrk +* A pointer to an array of 2 elements +* in which to return the X and Y components of a unit vector in the +* graphics coordinate system. The vector is tangential to the curve +* at the requested break, and points back along the drawn section of +* the curve. +* len +* A pointer to a "double" in which to return the +* length of the drawn curve, in the graphics coordinate system. + +* Returned Value: +* astCvBrk() +* The number of breaks which occurred in the curve. + +* Notes: +* - Currently, this function may not be used to return information +* about curves drawn using astPolyCurve. +* - All curves contain at least two breaks; one at the start and one +* at the end. This is true even if the start and end of the curve are +* coincident. However, if the entire curve was outside the plotting area +* (i.e. if the length of the drawn curve is zero), then it will have no +* breaks. +* - If no curve has yet been drawn by astGridLine or astCurve, then -1 is +* returned for the function value, and the function parameter values are +* left unchanged. +* - The returned information refers to the most recent curve drawn by +* astGridLine or astCurve, even if that curve was drawn by a Plot other than +* the one supplied to this function. +* - NULL pointers may be supplied for "brk", "vbrk" or "len", in which +* case the corresponding values are not returned. +* - Zero is returned by this function if an error has already occurred, +* or if this function should fail for any reason. + +*- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + int ret; /* The number of breaks in the curve. */ + +/* Check the global status. */ + if( !astOK ) return 0; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Information about the most recent curve drawn by astGridLine or astCurve is + stored in the external structure "Curve_data". Get the number of breaks + in the last curve. This is initialised to -1 in astInitPlot when the + virtual function table for this class is initialised. */ + ret = Curve_data.nbrk; + +/* If a curve has been drawn, store the length of the drawn curve if + required. */ + if( ret != -1 ){ + if( len ) *len = (double) Curve_data.length; + +/* If a legal break index has been supplied, return the position and + direction at the requested break (if required). */ + if( ibrk > 0 && ibrk <= ret ){ + if( brk ){ + brk[ 0 ] = (double) Curve_data.xbrk[ ibrk - 1 ]; + brk[ 1 ] = (double) Curve_data.ybrk[ ibrk - 1 ]; + } + if( vbrk ){ + vbrk[ 0 ] = (double) Curve_data.vxbrk[ ibrk - 1 ]; + vbrk[ 1 ] = (double) Curve_data.vybrk[ ibrk - 1 ]; + } + +/* If an illegal break index has been supplied (other than zero), report + an error, and set the number of breaks to zero. */ + } else if( ibrk ){ + if( ret > 0 ){ + astError( AST__BDBRK, "astCvBrk(%s): The supplied break index " + "(%d) should be in the range [1,%d].", status, astGetClass(this), + ibrk, ret ); + ret = 0; + } else { + astError( AST__BDBRK, "astCvBrk(%s): The most recent curve " + "plotted by method astGridLine or astCurve had no breaks.", status, + astGetClass(this) ); + } + } + } + +/* If an error has occurred, return 0. */ + if( !astOK ) ret = 0; + +/* Return the result. */ + return ret; + +} + +static void CrvLine( AstPlot *this, double xa, double ya, double xb, double yb, + const char *method, const char *class, int *status ){ +/* +* Name: +* CrvLine + +* Purpose: +* Draw a straight line between two points, with clipping. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void CrvLine( AstPlot *this, double xa, double ya, double xb, double yb, +* const char *method, const char *class ) + +* Class Membership: +* Plot member function. + +* Description: +* This functions draws a straight line from (xa,ya) to (xb,yb), breaking +* the line at the edges of the plotting area defined by Crv_xlo, Crv_xhi, +* Crv_ylo and Crv_yhi if Crv_clip is non-zero. If the line does not start +* at the end of the previous line plotted by this function, then +* information describing the break in the curve is stored in external +* arrays. + +* Parameters: +* xa +* The graphics X coordinate at the start of the line. +* ya +* The graphics Y coordinate at the start of the line. +* xb +* The graphics X coordinate at the end of the line. +* yb +* The graphics Y coordinate at the end of the line. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. + +* External Variables: +* Crv_ink = int (Read) +* If zero then no line is drawn even if the line intersects the +* plotting space, but break information (etc) is still returned. +* Crv_clip = double (Read) +* Clip lines at boundary of plotting space? +* Crv_xlo = double (Read) +* Lower x limit of the plotting space. +* Crv_xhi = double (Read) +* Upper x limit of the plotting space. +* Crv_ylo = double (Read) +* Lower y limit of the plotting space. +* Crv_yhi = double (Read) +* Upper y limit of the plotting space. +* Crv_tol = double (Read) +* The tolerance for determining if 2 points are coincident. +* Crv_out = int (Read/Write) +* Returned as zero if the line intersects the plotting space. +* Unchanged otherwise. +* Crv_xbrk = float * (Read/Write) +* Pointer to the next available element in an array of AST__PLOT_CRV_MXBRK +* values containing the graphics X coordinates at which each break +* in the plotted curve occurred. A break is recorded if the starting +* point of the current line is not the same as the end point of +* the previous line. +* Crv_ybrk = float * (Read/Write) +* Pointer to the next available element in an array of AST__PLOT_CRV_MXBRK +* values containing the graphics Y coordinates at which each break +* in the plotted curve occurred. +* Crv_vxbrk = float * (Read/Write) +* Pointer to the next available element in an array of AST__PLOT_CRV_MXBRK +* values containing the X component of the unit vector (within the +* graphics coordinate system) parallel to the tangent to the curve +* at each break. The sense is such that the vector always points back +* along the plotted section of the curve. +* Crv_vybrk = float * (Read/Write) +* Pointer to the next available element in an array of AST__PLOT_CRV_MXBRK +* values containing the Y component of the unit vector parallel to +* the tangent to the curve at each break. +* Crv_nbrk = int (Write) +* The number of breaks for which information is returned in Crv_xbrk, +* etc. +* Crv_len = float (Write) +* The length of the section of the curve which has been drawn so far. +* Crv_xl = double (Write) +* The graphics X coordinate at the end of the last line drawn. +* Crv_yl = double (Write) +* The graphics Y coordinate at the end of the last line drawn. +* Crv_vxl = double (Write) +* The X component of the unit vector along the last line drawn. +* Crv_vyl = double (Write) +* The Y component of the unit vector along the last line drawn. +* Grf_alpha = float (Read) +* The factor for scaling graphics X axis values into equal scaled +* X axis values. +* Grf_beta = float (Read) +* The factor for scaling graphics Y axis values into equal scaled +* Y axis values. + +*/ + +/* local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + double a1; /* Distance from B to the lower x boundary */ + double a2; /* Distance from B to the upper x boundary */ + double a3; /* Distance from B to the lower y boundary */ + double a4; /* Distance from B to the upper y boundary */ + double aamax; /* Distance from supplied point B to the plotable point A */ + double aamin; /* Distance from supplied point B to the plotable point B */ + double dl; /* Length of plotted line segment */ + double dx; /* Difference in x between supplied points */ + double dy; /* Difference in y between supplied points */ + double t; /* Temporary storage */ + double xam; /* Modified xa position */ + double xbm; /* Modified xb position */ + double yam; /* Modified ya position */ + double ybm; /* Modified yb position */ + int plot; /* True if a line can be plotted */ + +/* Check inherited global status. */ + if( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + dl = 0.0; + xam = 0.0; + xbm = 0.0; + yam = 0.0; + ybm = 0.0; + +/* Store the shifts in x and y. */ + dx = xb - xa; + dy = yb - ya; + +/* Do nothing if the line is of zero length. */ + if( dx == 0.0 && dy == 0.0 ) return; + +/* If either end is outside the zone, replace the given coordinates with + the end coordinates of the section of the line which lies within the + zone. */ + if( Crv_clip && ( xa < Crv_xlo || xa > Crv_xhi || + xb < Crv_xlo || xb > Crv_xhi || + ya < Crv_ylo || ya > Crv_yhi || + yb < Crv_ylo || yb > Crv_yhi ) ){ + +/* Find the distance from point B towards point A at which the + line cuts the two x bounds of the zone (distance at point B is + 0.0, and at point A is 1.0). */ + if( dx != 0.0 ){ + a1 = ( xb - Crv_xlo )/dx; + a2 = ( xb - Crv_xhi )/dx; + +/* Ensure that a1 represents the highest plottable offset, and a2 the + lowest. */ + if( a1 < a2 ){ + t = a1; + a1 = a2; + a2 = t; + } + +/* If the line joining A and B is vertical... */ + } else { + +/* If the line is within the plottable x range, indicate that all + offsets are plottable (as far as the x range is concerned at least). */ + if( ( xa > Crv_xlo || astEQUALS( xa, Crv_xlo, 1.0E8 ) ) && + ( xa < Crv_xhi || astEQUALS( xa, Crv_xhi, 1.0E8 ) ) ){ + a1 = DBL_MAX; + a2 = -DBL_MAX; + +/* If the line is ouside the plottable x range, indicate that no + offsets are plottable. */ + } else { + a1 = 0.0; + a2 = 0.0; + } + } + +/* Find the fractional distance from point A to point B at which the + line cuts the two y bounds of the zone. */ + if( dy != 0.0 ){ + a3 = ( yb - Crv_ylo )/dy; + a4 = ( yb - Crv_yhi )/dy; + +/* Ensure that a3 represents the highest plottable offset, and a4 the + lowest. */ + if( a3 < a4 ){ + t = a3; + a3 = a4; + a4 = t; + } + +/* If the line joining A and B is horizontal... */ + } else { + +/* If the line is within the plottable y range, indicate that all + offsets are plottable (as far as the y range is concerned at least). */ + if( ( ya > Crv_ylo || astEQUALS( ya, Crv_ylo, 1.0E8 ) ) && + ( ya < Crv_yhi || astEQUALS( ya, Crv_yhi, 1.0E8 ) ) ){ + a3 = DBL_MAX; + a4 = -DBL_MAX; + +/* If the line is ouside the plottable y range, indicate that no + offsets are plottable. */ + } else { + a3 = 0.0; + a4 = 0.0; + } + } + +/* Find the fractional distances from point A to point B at the ends + of the plotable line. */ + aamin = astMIN( 1.0, astMAX( 0.0, astMAX( a2, a4 ) ) ); + aamax = astMAX( 0.0, astMIN( 1.0, astMIN( a1, a3 ) ) ); + +/* Store the end coordinates of the line joining the plotable points. */ + if( aamax > aamin ){ + xam = xb - aamax*dx; + yam = yb - aamax*dy; + xbm = xb - aamin*dx; + ybm = yb - aamin*dy; + plot = 1; + +/* Get the unit vector along the line and the length of the plotted section. */ + dx *= Grf_alpha; + dy *= Grf_beta; + dl = sqrt( dx*dx + dy*dy ); + dx /= dl; + dy /= dl; + dl *= astMAX( 0.0, aamax - aamin ); + +/* Clear the "plot" flag if the line does not intersect the plotting area. */ + } else { + plot = 0; + } + +/* If both ends of the line are within the plotting zone, draw the whole + line between the supplied end points. */ + } else { + xam = xa; + yam = ya; + xbm = xb; + ybm = yb; + plot = 1; + +/* Get the length of the line and the unit vector along the line. */ + dx *= Grf_alpha; + dy *= Grf_beta; + dl = sqrt( dx*dx + dy*dy ); + dx /= dl; + dy /= dl; + } + +/* If a line is to be plotted... */ + if( plot ){ + +/* If this is the first line to be plotted in the current curve, save + the start of the line as a break, and indicate that some of the curve + falls within the plotting zone. */ + if( Crv_out ){ + Crv_nbrk = 1; + *(Crv_xbrk++) = (float) xam; + *(Crv_ybrk++) = (float) yam; + *(Crv_vxbrk++) = (float) dx; + *(Crv_vybrk++) = (float) dy; + Crv_out = 0; + +/* Set the length of the curve plotted so far to the length of this first + segment. */ + Crv_len = (float) dl; + +/* Start a poly line. */ + if( Crv_ink ) Bpoly( this, (float) xam, (float) yam, status ); + +/* If this is not the first line to be plotted... */ + } else { + +/* ... increment the length of the curve plotted so far. */ + Crv_len += (float) dl; + +/* If the start of this line is not coincident with the end + of the previous line, save the previous and current positions as + breaks in the curve. Note, the previous vector is reversed so that + it points back towards the drawn section of the curve. Report an + error if the arrays are full. */ + if( fabs( xam - Crv_xl ) > Crv_tol || + fabs( yam - Crv_yl ) > Crv_tol ){ + Crv_nbrk += 2; + if( Crv_nbrk > AST__PLOT_CRV_MXBRK ){ + astError( AST__CVBRK, "%s(%s): Number of breaks in plotted " + "curve exceeds %d.", status, method, class, AST__PLOT_CRV_MXBRK ); + } else { + *(Crv_xbrk++) = (float) Crv_xl; + *(Crv_ybrk++) = (float) Crv_yl; + *(Crv_vxbrk++) = (float) -Crv_vxl; + *(Crv_vybrk++) = (float) -Crv_vyl; + *(Crv_xbrk++) = (float) xam; + *(Crv_ybrk++) = (float) yam; + *(Crv_vxbrk++) = (float) dx; + *(Crv_vybrk++) = (float) dy; + } + +/* Start a poly line. */ + if( Crv_ink ) Bpoly( this, (float) xam, (float) yam, status ); + } + } + +/* Append a section to the current poly line. */ + if( Crv_ink ) Apoly( this, (float) xbm, (float) ybm, status ); + +/* Save the position and vector at the end of the current line. */ + Crv_xl = xbm; + Crv_yl = ybm; + Crv_vxl = dx; + Crv_vyl = dy; + } + +/* Return. */ + return; +} + + +static void Curve( AstPlot *this, const double start[], + const double finish[], int *status ){ +/* +*++ +* Name: +c astCurve +f AST_CURVE + +* Purpose: +* Draw a geodesic curve. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "plot.h" +c void astCurve( AstPlot *this, const double start[], +c const double finish[] ) +f CALL AST_CURVE( THIS, START, FINISH, STATUS ) + +* Class Membership: +* Plot method. + +* Description: +c This function draws a geodesic curve between two points in the +f This routine draws a geodesic curve between two points in the +* physical coordinate system of a Plot. The curve drawn is the +* path of shortest distance joining the two points (as defined by +c the astDistance function for the current Frame of the Plot). +f the AST_DISTANCE function for the current Frame of the Plot). +* For example, if the current Frame is a basic Frame, then the +* curve joining the two points will be a straight line in physical +* coordinate space. If the current Frame is more specialised and +* describes, for instance, a sky coordinate system, then the +* geodesic curve would be a great circle in physical coordinate +* space passing through the two sky positions given. +* +* Note that the geodesic curve is transformed into graphical +* coordinate space for plotting, so that a straight line in +* physical coordinates may result in a curved line being drawn if +* the Mapping involved is non-linear. Any discontinuities in the +* Mapping between physical and graphical coordinates are +c catered for, as is any clipping established using astClip. +f catered for, as is any clipping established using AST_CLIP. +* +c If you need to draw many geodesic curves end-to-end, then the +c astPolyCurve function is equivalent to repeatedly using +c astCurve, but will usually be more efficient. +f If you need to draw many geodesic curves end-to-end, then the +f AST_POLYCURVE routine is equivalent to repeatedly calling +f AST_CURVE, but will usually be more efficient. +* +c If you need to draw curves which are not geodesics, see astGenCurve +c or astGridLine. +f If you need to draw curves which are not geodesics, see AST_GENCURVE +f or AST_GRIDLINE. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +c start +f START( * ) = DOUBLE PRECISION (Given) +* An array, with one element for each axis of the Plot, giving +* the physical coordinates of the first point on the geodesic +* curve. +c finish +f FINISH( * ) = DOUBLE PRECISION (Given) +* An array, with one element for each axis of the Plot, giving +* the physical coordinates of the second point on the geodesic +* curve. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +c - No curve is drawn if either of the "start" or "finish" arrays +c contains any coordinates with the value AST__BAD. +f - No curve is drawn if either of the START or FINISH arrays +f contains any coordinates with the value AST__BAD. +* - An error results if the base Frame of the Plot is not 2-dimensional. +* - An error also results if the transformation between the +* current and base Frames of the Plot is not defined (i.e. the +* Plot's TranInverse attribute is zero). +*-- +*/ +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + const char *class; /* Object class */ + const char *method; /* Current method */ + int naxes; /* No. of axes in the base Frame */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Store the current method, and the class of the supplied object for use + in error messages.*/ + method = "astCurve"; + class = astGetClass( this ); + +/* Check the base Frame of the Plot is 2-D. */ + naxes = astGetNin( this ); + if( naxes != 2 && astOK ){ + astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " + "Frame of the supplied %s is invalid - this number should " + "be 2.", status, method, class, naxes, class ); + } + +/* Initialise the bounding box for primitives produced by this call. */ + if( !Boxp_freeze ) { + Boxp_lbnd[ 0 ] = FLT_MAX; + Boxp_lbnd[ 1 ] = FLT_MAX; + Boxp_ubnd[ 0 ] = FLT_MIN; + Boxp_ubnd[ 1 ] = FLT_MIN; + } + +/* Indicate that the GRF module should re-calculate it's cached values + (in case the state of the graphics system has changed since the last + thing was drawn). */ + RESET_GRF; + +/* Draw the curve. The break information is stored in an external structure + where it can be accessed by public methods which return information + about the most recently drawn curve. */ + CurvePlot( this, start, finish, 1, &Curve_data, method, class, status ); + +/* Ensure all lines are flushed to the graphics system. */ + Fpoly( this, method, class, status ); + +/* Return. */ + return; +} + +static void CurvePlot( AstPlot *this, const double *start, const double *finish, + int ink, AstPlotCurveData *cdata, const char *method, + const char *class, int *status ){ +/* +* +* Name: +* CurvePlot + +* Purpose: +* Draw a geodesic curve. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void CurvePlot( AstPlot *this, const double *start, const double *finish, +* int ink, AstPlotCurveData *cdata, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function draws a geodesic curve between the supplied starting and +* finishing positions. The algorithm used can handle discontinuities in the +* Mapping between the current Frame and graphics coordinates, and +* information describing any breaks in the curve (including the start and +* end of the curve) are returned in the supplied AstPlotCurveData structure. + +* Parameters: +* this +* Pointer to the Plot. +* start +* A pointer to a an array holding the coordinates of the start of the +* curve within the current Frame of the Plot. +* finish +* A pointer to a an array holding the coordinates of the finish of the +* curve within the current Frame of the Plot. +* ink +* If zero, the curve is not actually drawn, but information about +* the breaks is still returned. If non-zero, the curve is also drawn. +* cdata +* A pointer to a structure in which to return information about the +* breaks in the curve. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Notes: +* - No curve is draw if the "start" or "finish" arrays contains any bad +* values, or if a NULL pointer is supplied for "cdata". No errors are +* reported in these cases. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + double d[ CRV_NPNT ]; /* Offsets to evenly spaced points along curve */ + double x[ CRV_NPNT ]; /* X coords at evenly spaced points along curve */ + double y[ CRV_NPNT ]; /* Y coords at evenly spaced points along curve */ + double tol; /* Absolute tolerance value */ + int i; /* Loop count */ + int naxes; /* No. of axes in the base Frame */ + int ok; /* Are all start coords good? */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Get the number of axes in the current Frame. */ + naxes = astGetNout( this ); + +/* Check the "start" and "finish" parameter for bad values. */ + ok = 1; + for( i = 0; i < naxes; i++ ) { + if( start[ i ] == AST__BAD || finish[ i ] == AST__BAD ){ + ok = 0; + break; + } + } + +/* Check that the "cdata" pointer can be used. */ + if( !cdata ) ok = 0; + +/* Only proceed if the parameters are OK, and there has been no error. */ + if( ok && astOK ){ + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + astGrfAttrs( this, AST__CURVE_ID, 1, GRF__LINE, method, class ); + +/* Ensure the globals holding the scaling from graphics coords to equally + scaled coords are available. */ + GScales( this, NULL, NULL, method, class, status ); + +/* Set up the externals used to communicate with the Map3 function... + The number of axes in the physical coordinate system (i.e. the current + Frame). */ + Map3_ncoord = naxes; + +/* A pointer to the Plot, the Curretn Frame, and and Mapping. */ + Map3_plot = this; + Map3_frame = astGetFrame( this, AST__CURRENT ); + Map3_map = astGetMapping( this, AST__BASE, AST__CURRENT ); + +/* The physical coordinates at the start of the curve. */ + Map3_origin = start; + +/* The physical coordinates at the end of the curve. */ + Map3_end = finish; + +/* The scale factor to convert "dist" values into physical offset values. */ + Map3_scale = astDistance( Map3_frame, start, finish ); + +/* Convert the tolerance from relative to absolute graphics coordinates. */ + tol = astGetTol( this )*astMAX( this->xhi - this->xlo, + this->yhi - this->ylo ); + +/* Now set up the external variables used by the Crv and CrvLine function. */ + Crv_scerr = ( astGetLogPlot( this, 0 ) || + astGetLogPlot( this, 1 ) ) ? 100.0 : 1.5; + Crv_ux0 = AST__BAD; + Crv_tol = tol; + Crv_limit = 0.5*tol*tol; + Crv_map = Map3; + Crv_ink = ink; + Crv_xlo = this->xlo; + Crv_xhi = this->xhi; + Crv_ylo = this->ylo; + Crv_yhi = this->yhi; + Crv_out = 1; + Crv_xbrk = cdata->xbrk; + Crv_ybrk = cdata->ybrk; + Crv_vxbrk = cdata->vxbrk; + Crv_vybrk = cdata->vybrk; + Crv_clip = astGetClip( this ) & 1; + +/* Set up a list of points spread evenly over the curve. */ + for( i = 0; i < CRV_NPNT; i++ ){ + d[ i ] = ( (double) i)/( (double) CRV_NSEG ); + } + +/* Map these points into graphics coordinates. */ + Map3( CRV_NPNT, d, x, y, method, class, status GLOBALS_NAME ); + +/* Use Crv and Map3 to draw the curve. */ + Crv( this, d, x, y, 0, NULL, NULL, method, class, status ); + +/* End the current poly line. */ + Opoly( this, status ); + +/* Tidy up the static data used by Map3. */ + Map3( 0, NULL, NULL, NULL, method, class, status GLOBALS_NAME ); + +/* If no part of the curve could be drawn, set the number of breaks and the + length of the drawn curve to zero. */ + if( Crv_out ) { + Crv_nbrk = 0; + Crv_len = 0.0F; + +/* Otherwise, add an extra break to the returned structure at the position of + the last point to be plotted. */ + } else { + Crv_nbrk++; + if( Crv_nbrk > AST__PLOT_CRV_MXBRK ){ + astError( AST__CVBRK, "%s(%s): Number of breaks in curve " + "exceeds %d.", status, method, class, AST__PLOT_CRV_MXBRK ); + } else { + *(Crv_xbrk++) = (float) Crv_xl; + *(Crv_ybrk++) = (float) Crv_yl; + *(Crv_vxbrk++) = (float) -Crv_vxl; + *(Crv_vybrk++) = (float) -Crv_vyl; + } + } + +/* Store extra information about the curve in the returned structure, and + purge any zero length sections. */ + if( cdata ){ + cdata->length = Crv_len; + cdata->out = Crv_out; + cdata->nbrk = Crv_nbrk; + PurgeCdata( cdata, status ); + } + +/* Annul the Frame and Mapping. */ + Map3_frame = astAnnul( Map3_frame ); + Map3_map = astAnnul( Map3_map ); + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, AST__CURVE_ID, 0, GRF__LINE, method, class ); + + } + +/* Return. */ + return; + +} + + +static AstPointSet *DefGap( AstPlot *this, double *gaps, int *ngood, + double *frac, int *inval, const char *method, + const char *class, int *status ){ +/* +* Name: +* DefGap + +* Purpose: +* Find default gap sizes for the tick marks on the axes of a 2-D +* physical coordinate system. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* AstPointSet *DefGap( AstPlot *this, double *gaps, int *ngood, +* double *frac, int *inval, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot method. + +* Description: +* This function returns default gap sizes for each axis in a 2-D Frame. +* The values are found by first obtaining a grid of points spread over +* the region containing good physical coordinates. The physical +* coordinate values (non-normalized) for each axis are sorted into +* increasing order. +* +* For linearly spaced tick marks, a set of quantile axis values is then +* found, and the median of the gaps between these quantiles is returned +* as the default gap for the axis. +* +* For logarithmically spaced tick marks, the returned gap size is the +* ratio between adjacent tick mark values, chosen to give an optimal +* number of ticks between the maximum and minimum axis values found in +* the grid. + +* Parameters: +* this +* Pointer to a Plot. +* gaps +* Pointer to an array in which to return the default gap value for +* each axis. +* ngood +* Pointer to an array in which toi return the number of good +* values in the returned PointSet for each axis. +* frac +* Pointer to a double in which to return the fraction of the +* plotting area containing good physical coordinates. +* inval +* Pointer to a location at which to return a flag indicating if +* any bad physical coordinates were encountered. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to a PointSet holding the physical coordinate values at a +* set of points spread across the plotting area. The values on each +* axis are sorted into increasing order. The values will not have +* been normalized. + +* Notes: +* - The returned PointSet should be annulled when no longer needed. +* - This function assumes that the physical coordinate system is 2 +* dimensional, and it should not be used if this is not the case. +* - Gap sizes of 1.0, zero good points, and a NULL pointer are returned +* if an error has already occurred, or if this function should fail for +* any reason. + +*/ + +/* Local Variables: */ + AstPointSet *pset1; /* Pointer to PointSet holding graphics coords */ + AstPointSet *pset2; /* Pointer to PointSet holding physical coords */ + double **ptr1; /* Pointer to graphics axis values */ + double **ptr2; /* Pointer to physical axis values */ + double dran; /* Dynamic range */ + double maxv; /* Maximum axis value */ + double minv; /* Minimum axis value */ + double qgap[ MAJTICKS_OPT ];/* Gaps between physical coordinate quantiles */ + int dim; /* Dimension of grid */ + int dk; /* The number of points between quantiles */ + int i; /* The quantile index */ + int j; /* Axis index */ + int k; /* Index into the sorted array of axis values */ + int logticks; /* Logarithmically spaced tick marks? */ + int n; /* Target number fo ticks */ + int psize; /* Total number of axis value */ + +/* Initialise the returned values. */ + gaps[ 0 ] = 1.0; + gaps[ 1 ] = 1.0; + ngood[ 0 ] = 0; + ngood[ 1 ] = 0; + *frac = 0.0; + *inval = 0; + +/* Check global status. */ + if( !astOK ) return NULL; + +/* Get two PointSets, one holding a grid of 2D graphics coordinates, + and one holding the corresponding (non-normalized) physical + coordinates. */ + dim = 0; + *frac = GoodGrid( this, &dim, &pset1, &pset2, method, class, status ); + +/* Get pointers to the data values in each PointSet. */ + ptr1 = astGetPoints( pset1 ); + ptr2 = astGetPoints( pset2 ); + +/* Store the number of elements in each PointSet. */ + psize = astGetNpoint( pset1 ); + +/* For each axis... */ + for( j = 0; j < 2 && astOK; j++ ){ + +/* Sort the axis values into increasing order. Any bad values are stored at + the end of the array on return. */ + qsort( (void *) ptr2[ j ], (size_t) psize, sizeof(double), Compared ); + +/* Count the number of non-bad values returned. */ + ngood[ j ] = CountGood( psize, ptr2[ j ], status ); + +/* Set the returned flag to indicate if any bad values were found. */ + if( ngood[ j ] < psize ) *inval = 1; + +/* Report an error if there are too few good points. */ + if( ngood[ j ] < MAJTICKS_OPT ){ + astError( AST__VSMAL, "%s(%s): The range of coordinate values " + "covered by axis %d is too small to plot.", status, method, + class, j + 1 ); + break; + } + +/* Get the maximum and minimum axis value */ + minv = ptr2[ j ][ 0 ]; + maxv = ptr2[ j ][ ngood[ j ] - 1 ]; + +/* See if ticks on this axis are spaced linearly or logarithmically. If a + value has been set for LogTicks used it, otherwise find a default value. + The default is 0 unless LogPlot is non-zero, the axis range does not + encompass zero and and the dynamic range is 90 or more. Set this + default value explicitly so that later functions will pick it up (it will + be cleared at the end of the astGrid function). */ + if( astTestLogTicks( this, j ) ) { + logticks = astGetLogTicks( this, j ); + } else { + logticks = 0; + if( astGetLogPlot( this, j ) && minv*maxv > 0.0 ) { + dran = maxv/minv; + if( dran >= 90.0 || dran <= 1.0/90.0 ) logticks = 1; + } + astSetLogTicks( this, j, logticks ); + } + +/* If no value has been supplied for LogLabel use the value of LogTicks + as the default. */ + if( !astTestLogLabel( this, j ) ) astSetLogLabel( this, j, logticks ); + +/* For linear gaps, find the gaps between adjacent evenly spaced quantiles. + The number of quantiles used equals the optimal number of major tick + marks. */ + if( !logticks ) { + dk = (int)( (double)ngood[ j ]/MAJTICKS_OPT ); + i = 0; + for( k = dk; k < ngood[ j ] && i < MAJTICKS_OPT; k += dk ){ + qgap[ i++ ] = ptr2[ j ][ k ] - ptr2[ j ][ k - dk ]; + } + +/* Find the median of the gaps between adjacent quantiles. */ + qsort( (void *) qgap, (size_t) i, sizeof(double), Compared ); + gaps[ j ] = qgap[ i/2 ]; + +/* If the test gap size is zero, use a fraction of the total range. Report + an error if the total range is zero. */ + if( gaps[ j ] <= 0.0 ){ + gaps[ j ] = ( ptr2[ j ][ ngood[ j ] - 1 ] - ptr2[ j ][ 0 ] )/MAJTICKS_OPT;; + if( gaps[ j ] <= 0.0 ){ + astError( AST__VSMAL, "%s(%s): The range of coordinate values " + "covered by axis %d is too small to plot.", status, method, + class, j + 1 ); + } + } + +/* For logarithmic gaps, use the Nth root of the ratio of the maximum and + minimum data value found. */ + } else if( astOK ) { + +/* Report an error if the max and min values are of opposite signs or + zero or equal. */ + if( maxv*minv <= 0.0 ) { + astError( AST__ZERAX, "%s(%s): The range of coordinate values " + "covered by axis %d includes the origin and so " + "logarithmic ticks cannot be produced.", status, method, + class, j + 1 ); + + } else if( maxv == minv ) { + astError( AST__VSMAL, "%s(%s): The range of coordinate values " + "covered by axis %d is too small to plot.", status, method, + class, j + 1 ); + +/* Otherwise find the gap to use. */ + } else { + +/* Store the maximum and minimum number of major tick marks along each + axis. These numbers are reduced if only a small part of the plotting + area contains valid coordinates, so that the tick marks do not end up + to close together. */ + n = (int) ( 0.5 + MAJTICKS_OPT*sqrt( *frac ) ); + if( n < 5 ) n = 5; + +/* Choose a gap size which makes this many gaps. */ + gaps[ j ] = pow( maxv/minv, 1.0/( n - 1.0 ) ); + } + } + } + +/* Annul the PointSet holding Graphics coordinates. */ + pset1 = astAnnul( pset1 ); + +/* If an error has occurred, annul the PointSet holding physical + coordinates, and return gaps of 1.0. */ + if( !astOK ) { + pset2 = astAnnul( pset2 ); + gaps[ 0 ] = 1.0; + gaps[ 1 ] = 1.0; + ngood[ 0 ] = 0; + ngood[ 1 ] = 0; + *frac = 0.0; + *inval = 0; + } + +/* Return the physical PointSet. */ + return pset2; + +} + +static void DrawAxis( AstPlot *this, TickInfo **grid, double *labelat, + double *gap, const char *method, const char *class, int *status ){ +/* +* +* Name: +* DrawAxis + +* Purpose: +* Draw a curve joining the major tick marks. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void DrawAxis( AstPlot *this, TickInfo **grid, double *labelat, +* double *gap, const char *method, const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function draws a curve through interior tick marks on both axes. +* The curve is drawn even if it has already been drawn as part of a +* grid of curves, because it may have been assigned different graphics +* attributes to the grid curves. + +* Parameters: +* this +* A pointer to the Plot. +* grid +* A pointer to an array of two TickInfo pointers (one for each axis), +* each pointing to a TickInfo structure holding information about +* tick marks on the axis. See function GridLines. +* labelat +* A pointer to a 2 element array giving the constant axis values at +* which tick marks are put. Element 0 should give the axis 1 value at +* which tick marks for axis 0 are placed. Element 1 should give the +* axis 0 value at which tick marks for axis 1 are placed. +* gap +* Pointer to array of two values holding the gap between major +* tick marks on the two axes. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Notes: +* - This function assumes the current Frame of the Plot is 2 +* dimensional, and it should not be called if this is not the case. + +*/ + +/* Local Variables: */ + AstFrame *frm; /* Pointer to current Frame */ + AstPlotCurveData cdata;/* Somewhere to put the unneeded curve information */ + TickInfo *info; /* Pointer to the TickInfo for the current axis */ + double *value; /* Current tick value */ + double bot; /* Lowest axis value to be displayed */ + double diff; /* Difference between adjacent tick marks */ + double udiff; /* Used section length */ + double start[ 2 ]; /* The start of the curve in physical coordinates */ + double tmp; /* Temporary storage */ + double top; /* Highest axis value to be displayed */ + int axis; /* Current axis index */ + int axisid; /* ID value for current axis plotting attributes */ + int logticks; /* Are major ticks spaced logarithmically? */ + int tick; /* Current tick index */ + +/* Check the global status. */ + if( !astOK ) return; + +/* Not the id value for the first axis. */ + axisid = AST__AXIS1_ID; + +/* Get a pointer to the current Frame. */ + frm = astGetFrame( this, AST__CURRENT ); + +/* Consider drawing a curve parallel to each axis in turn. */ + for( axis = 0; axis < 2; axis++ ){ + +/* Establish the correct graphical attributes for this axis as defined by + attributes with the supplied Plot. */ + astGrfAttrs( this, axisid, 1, GRF__LINE, method, class ); + +/* Check the axis is required. */ + if( astGetDrawAxes( this, axis ) ){ + +/* If the tick marks have been placed round the edges of the plotting + area, we do not need to draw the curves. */ + if( labelat[ axis ] != AST__BAD ){ + +/* Get the max and min values allowed on this axis. */ + bot = astGetBottom( frm, axis ); + top = astGetTop( frm, axis ); + if( bot > top ) { + tmp = top; + top = bot; + bot = tmp; + } + +/* Get a pointer to the structure containing information describing the + positions of the major tick marks along the current axis. */ + info = grid[ axis ]; + +/* Get a pointer to the axis value at the first major tick mark. */ + value = info->ticks; + +/* See if the major tick marks are logarithmically spaced on this axis. */ + logticks = astGetLogTicks( this, axis ); + +/* Initialise the difference between major tick marks. */ + diff = logticks ? 0.0 : gap[ axis ]; + +/* Loop round all ticks. */ + for( tick = 0; tick < info->nmajor; tick++, value++ ){ + +/* Update the difference between major tick marks if we are producing + logarithmically spaced ticks (in which "gap" is a ratio, not a + difference). */ + if( logticks ) diff = (*value)*( gap[ axis ] - 1.0 ); + +/* Note the starting point for this section. */ + start[ axis ] = *value; + start[ 1 - axis ] = labelat[ axis ]; + +/* If this is the first tick, draw an axis section going "backwards" in + case the first tick isn't at the lower visible bound. Limit the length + of this backwards section so that it does not extend beyond the minimum + axis value. */ + if( tick == 0 ) { + udiff = *value - bot; + if( udiff > diff ) udiff = diff; + if( udiff > 0.0 ) { + AxPlot( this, axis, start, -udiff, 1, &cdata, method, + class, status ); + } + } + +/* Limit the length of the section so that it does not extend beyond the + maximum axis value. */ + udiff = ( *value + diff > top ) ? top - *value : diff; + +/* Do not draw zero length sections. */ + if( udiff > 0.0 ) { + +/* Draw a curve parallel to the current axis, starting at the tick mark, + with length equal to the gap between tick marks. Do not draw sections + of the curve which are outside the primary domains of the physical axes. */ + AxPlot( this, axis, start, udiff, 1, &cdata, method, + class, status ); + } + + } + +/* Once the last section has been drawn, draw another axis section in case the + last tick isn't at the upper visible bound. Limit the length of this + section so that it does not extend beyond the maximum axis value. */ + udiff = top - start[ axis ]; + if( udiff > diff ) udiff = diff; + if( udiff > 0.0 ) { + AxPlot( this, axis, start, udiff, 1, &cdata, method, + class, status ); + } + } + } + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, axisid, 0, GRF__LINE, method, class ); + +/* Set up the id value for the next axis. */ + axisid = AST__AXIS2_ID; + + } + +/* Free the pointer to the current Frame. */ + frm = astAnnul( frm ); + +} + + +static AstPlotCurveData **DrawGrid( AstPlot *this, TickInfo **grid, int drawgrid, + const char *method, const char *class, int *status ){ +/* +* Name: +* DrawGrid + +* Purpose: +* Draw a grid of lines at the major tick mark positions on both axes. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* AstPlotCurveData **DrawGrid( AstPlot *this, TickInfo **grid, int drawgrid, +* const char *method, const char *class ) + +* Class Membership: +* Plot method. + +* Description: +* This function draw a grid of curves at the major tick mark +* positions on both axes, and returns information describing the +* breaks in the curves. If short tick marks are required rather +* than long curves (as specified by the Grid attribute of the supplied +* Plot), then the curves are not drawn but the break information is +* still returned. + +* Parameters: +* this +* Pointer to a Plot. +* grid +* A pointer to an array of two pointers (one for each axis), each +* pointing to a TickInfo structure. These describe the positions +* of the tick marks and should have been produced by function +* GridLines. +* drawgrid +* If non-zero, draw a grid of curves marking the major axis +* values. Otherwise, tick marks will be drawn at these values later. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. + +* Returned Value: +* A pointer to an array of two AstPlotCurveData pointers (one for each axis), +* each pointing to an array of AstPlotCurveData structures (one for each tick +* value). + +* Notes: +* - This function assumes that the physical coordinate system is 2 +* dimensional, and it should not be used if this is not the case. +* - If an error has already occurred, or if this function should fail +* for any reason, then a NULL pointer is returned. + +*/ + +/* Local Variables: */ + AstPlotCurveData **cdata;/* The returned pointer */ + AstPlotCurveData *cdt; /* Pointer to break info. for current tick mark */ + AstPlotCurveData tcdt; /* Pointer to break info. for current curve section */ + TickInfo *info; /* Tick mark information for a single axis */ + double start[ 2 ]; /* Strting position for current curve section */ + double total_length; /* Total curve length for all axis ticks */ + int i; /* Axis index */ + int j; /* Tick mark index */ + int k; /* Curve section index */ + +/* Check the global status. */ + if( !astOK ) return NULL; + +/* Allocate memory to hold two pointers, each pointing to an array of + AstPlotCurveData structure. */ + cdata = (AstPlotCurveData **) astMalloc( 2*sizeof( AstPlotCurveData *) ); + +/* If succesful, initialise the pointers. */ + if( astOK ){ + cdata[ 0 ] = NULL; + cdata[ 1 ] = NULL; + +/* Draw the curves marking the major tick values on each axis. If no grid is + required, we still do this in order to get information about the breaks + in the curves which will be used later to decide where to put the labels, + but we use "invisible ink". */ + for( i = 0; i < 2; i++ ){ + +/* Get a pointer to the TickInfo structure for this axis holding information + about where to put tick marks on this axis. */ + info = grid[ i ]; + +/* Allocate memory to hold information describing the breaks in each tick + mark curve. This takes the form of an array of AstPlotCurveData structures, + one for each tick mark. */ + cdata[ i ] = (AstPlotCurveData *) astMalloc( sizeof(AstPlotCurveData)* + (size_t) info->nmajor ); + +/* Check the pointer can be used. */ + if( astOK ){ + +/* Initialise a pointer to the first AstPlotCurveData structure for this axis. */ + cdt = cdata[ i ]; + total_length = 0.0; + +/* Do each tick mark. */ + for( j = 0; j < info->nmajor; j++ ){ + +/* Store the starting point of the first section of the curve. */ + start[ i ] = (info->ticks)[ j ]; + start[ 1 - i ] = (info->start)[ 0 ]; + +/* Draw the first section of the curve parallel to the other axis, starting + at the values in "start", and extending for a length given in the TickInfo + structure. We use invisible ink if short tick marks are required instead + of a grid of curves. */ + AxPlot( this, 1 - i, start, (info->length)[ 0 ], + drawgrid, cdt, method, class, status ); + +/* Now draw any other sections in the curve. */ + for( k = 1; k < info->nsect; k++ ){ + +/* Modify the starting value on the other axis. The starting value on + the current axis remains set to the tick mark value. */ + start[ 1 - i ] = (info->start)[ k ]; + +/* Draw the curve, the information describing the breaks goes into + temporary storage in the local structure "tcdt". */ + AxPlot( this, 1 - i, start, (info->length)[ k ], + drawgrid, &tcdt, method, class, status ); + +/* Concatenate the break information for this section with the break + information describing the previous sections. */ + AddCdt( cdt, &tcdt, method, class, status ); + + } + +/* Increment the total length of curves drawn for all ticks on this axis. */ + total_length += cdt->length; + +/* Point to the AstPlotCurveData structure for the next tick mark. */ + cdt++; + + } + +/* Report an error if the total length of all curves on this axis is zero. + This can be caused for instance by bugs in the algorithm for finding + major tick values (which may cause AST__BAD tick mark values). */ + if( total_length == 0.0 && astOK ) { + astError( AST__INTER, "%s(%s): No grid curves can be drawn for " + "axis %d.", status, method, class, i + 1 ); + } + + } + + } + + } + +/* If an error has occurred, clean up the returned structures. */ + if( !astOK ) cdata = CleanCdata( cdata, status ); + +/* Return. */ + return cdata; + +} + +static int DrawRegion( AstPlot *this, AstFrame *frm, const char *method, + const char *class, int *status ){ +/* +* +* Name: +* DrawRegion + +* Purpose: +* Draw the outline of a Region. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int DrawRegion( AstPlot *this, AstFrame *frm, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* If the current Frame in the supplied Plot is a Region, this function +* draws a curve marking the outline of the Region. It returns without +* action otherwise. + +* Parameters: +* this +* Pointer to the Plot. +* frm +* Pointer to the current Frame in the Plot (possibly a Region). +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Non-zero if and only if a Region outline was drawn. + +*/ + +/* Local Variables: */ + AstMapping *map; /* Mapping with Region masking included */ + AstPlotCurveData cdata; /* Stores information about curve breaks */ + AstRegion **comps; /* List of component Regions */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + double d[ CRV_NPNT ]; /* Offsets to evenly spaced points along curve */ + double tol; /* Absolute tolerance value */ + double x[ CRV_NPNT ]; /* X coords at evenly spaced points along curve */ + double y[ CRV_NPNT ]; /* Y coords at evenly spaced points along curve */ + int i; /* Loop count */ + int icomp; /* Index of component Region */ + int ncomp; /* Number of component Regions */ + int result; /* The returned value */ + +/* Initialise */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Check the current Frame is a Region, and is of a class that implements + the astRegTrace method. */ + if( astIsARegion( frm ) && + astRegTrace( (AstRegion *) frm, 0, NULL, NULL ) ){ + +/* Set up the externals used to communicate with the Map5 function... + The number of axes in the physical coordinate system (i.e. the + Region). */ + Map5_ncoord = astGetNaxes( frm ); + +/* A pointer to the Plot, the Region, and the Mapping. */ + Map5_plot = this; + Map5_region = (AstRegion *) frm; + +/* Also store a pointer to the Mapping, ensuring that the Mapping does + not contain any masking effects from the Region. */ + map = astGetMapping( this, AST__BASE, AST__CURRENT ); + Map5_map = astRemoveRegions( map ); + map = astAnnul( map ); + +/* Convert the tolerance from relative to absolute graphics coordinates. + Make the tolerance smaller by a factor of 10 because Regions + (specifically Polygonsd) can have very crinkly edges. */ + tol = 0.1* astGetTol( this )*astMAX( this->xhi - this->xlo, + this->yhi - this->ylo ); + +/* Ensure the globals holding the scaling from graphics coords to equally + scaled coords are available. */ + GScales( this, NULL, NULL, method, class, status ); + +/* Now set up the external variables used by the Crv and CrvLine function. */ + Crv_scerr = ( astGetLogPlot( this, 0 ) || + astGetLogPlot( this, 1 ) ) ? 100.0 : 1.5; + Crv_ux0 = AST__BAD; + Crv_tol = tol; + Crv_limit = 0.5*tol*tol; + Crv_map = Map5; + Crv_ink = 1; + Crv_xlo = this->xlo; + Crv_xhi = this->xhi; + Crv_ylo = this->ylo; + Crv_yhi = this->yhi; + Crv_out = 1; + Crv_xbrk = cdata.xbrk; + Crv_ybrk = cdata.ybrk; + Crv_vxbrk = cdata.vxbrk; + Crv_vybrk = cdata.vybrk; + Crv_clip = astGetClip( this ) & 1; + +/* Attempt to split the Region into a set of disjoint component Regions. */ + comps = astRegSplit( (AstRegion *) frm, &ncomp ); + +/* Draw each one. */ + for( icomp = 0; icomp < ncomp; icomp++ ) { + +/* A pointer to the Region. */ + Map5_region = comps[ icomp ]; + +/* Set up a list of points spread evenly over the curve. */ + for( i = 0; i < CRV_NPNT; i++ ){ + d[ i ] = ( (double) i)/( (double) CRV_NSEG ); + } + +/* Map these points into graphics coordinates. */ + Map5( CRV_NPNT, d, x, y, method, class, status GLOBALS_NAME ); + +/* Use Crv and Map5 to draw the curve. */ + Crv( this, d, x, y, 0, NULL, NULL, method, class, status ); + +/* End the current poly line. */ + Opoly( this, status ); + +/* Tidy up the static data used by Map5. */ + Map5( 0, NULL, NULL, NULL, method, class, status GLOBALS_NAME ); + +/* Annul the component Region pointer. */ + comps[ icomp ] = astAnnul( Map5_region ); + } + +/* Free the memory holding the list of component Region pointers. */ + comps = astFree( comps ); + +/* Annul the Mapping. */ + Map5_map = astAnnul( Map5_map ); + +/* Indicate the outline was drawn. */ + result = 1; + } + +/* Return. */ + return result; +} + +static void DrawText( AstPlot *this, int ink, int esc, const char *text, + float x, float y, const char *just, float upx, + float upy, float *xbn, float *ybn, float *drop, + const char *method, const char *class, int *status ){ +/* +* Name: +* DrawText + +* Purpose: +* Draw a character string, potentially including superscripts and +* subscripts. + +* Synopsis: +* #include "plot.h" +* void DrawText( AstPlot *this, int ink, int esc, const char *text, +* float x, float y, const char *just, float upx, +* float upy, float *xbn, float *ybn, float *drop, +* const char *method, const char *class, int *status ) + +* Description: +* This function displays a character string at a given position +* using a specified up-vector, optionally interpreting any Plot escape +* sequences contained within the text. It also returns its bounding +* box. + +* Parameters: +* this +* The plot. +* ink +* If zero, nothing is drawn but the bounding box is still returned. +* esc +* Should escape sequences be interpreted? They will be printed +* literally otherwise. +* text +* Pointer to a null-terminated character string to be displayed. +* x +* The graphics X coordinate of the label's reference point. +* y +* The graphics Y coordinate of the label's reference point. +* just +* Pointer to a null-terminated character string identifying the +* reference point for the text being drawn. The first character in +* this string identifies the reference position in the "up" direction +* and may be "M", "B", "C" or "T" (for bottom, baseline, centre or +* top). The second character identifies the side-to-side reference +* position and may be "L", "C" or "R" (for left, centre or right). The +* string is case-insensitive, and only the first two characters are +* significant. +* upx +* The x component of the up-vector for the text. Positive values +* always refer to displacements from left to right on the screen, +* even if the graphics x axis increases in the opposite sense. +* upy +* The y component of the up-vector for the text. Positive values +* always refer to displacements from left to right on the screen, +* even if the graphics y axis increases in the opposite sense. +* xbn +* An array in which is returned the x coordinates at the corners +* of the bounding box. The order is: bottom left, top left, top +* right, bottom right. +* ybn +* An array in which is returned the Y coordinates at the corners +* of the bounding box (see xbn). +* drop +* Address of a float in which to return the distance between the +* bottom of the bounding box and the baseline of normal text. May +* be NULL. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Notes: +* - The "B" option for the justification in the "up" direction refers +* to the base-line on which the text is written. Some characters +* ("y", "p", "g", etc) descend below this line. In addition, if the +* supplied text string includes any escape sequences which produce +* sub-scripts, then these will also descend below the base-line. To +* justify the bottom of the entire string (instead of just the +* base-line), specify "M" instead of "B" in the justification string. +* - See function astFindEscape for details of the supported escape +* sequences. +*/ + + +/* Local Variables: */ + astDECLARE_GLOBALS + char *a; + char *lt; + char cc; + const char *lj; + double ncol; + double nfont; + double nsize; + double nstyle; + double nwidth; + float alpha_hi; + float alpha_lo; + float beta_lo; + float beta_hi; + float cy; + float cx; + float dy; + float dx; + float height; + float hmx; + float hmy; + float ly; + float lx; + float rx; + float rlen; + float rise; + float rxu; + float ryu; + float ry; + float tdrop; + float tybn[ 4 ]; + float txbn[ 4 ]; + float ulen; + float uyu; + float uxu; + float uy; + float ux; + float width; + float x0; + float y0; + int estype; + int esval; + int got_esc; + int grfcap; + int i; + int nc; + +/* Check the global error status, and that we have something to plot, and + the reference position is good, and that the up vector is not zero. */ + if ( !astOK || !text || !text[ 0 ] || x == AST__BAD || y == AST__BAD || + ( upx == 0.0 && upy == 0.0 ) ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Initialise variables to avoid compiler warnings. */ + rx = 0.0f; + ry = 0.0f; + x0 = 0.0f; + y0 = 0.0f; + +/* Get an up vector which refers to the graphics coordinates in their correct + senses (the supplied values are reversed if the corresponding axis is + reversed). */ + ux = ( this->xrev ) ? -upx : upx; + uy = ( this->yrev ) ? -upy : upy; + +/* Find a vector which points from left to right along the text + baseline, taking account of any difference in the scales of the x + and y axes (is possible). This also scales the up vector so that it + has a length equal to the height of normal text, and scales the right + vector to have the same length (on the screen) as the up vector. */ + RightVector( this, &ux, &uy, &rx, &ry, method, class, status ); + +/* Create a unit right vector. */ + rlen = sqrt( rx*rx + ry*ry ); + rxu = rx/rlen; + ryu = ry/rlen; + +/* Create a unit up vector. */ + ulen = sqrt( ux*ux + uy*uy ); + uxu = ux/ulen; + uyu = uy/ulen; + +/* Some older GRF modules cannot plot strings with vertical justification + of "M". Check the capabilities of the grf module, and, if necessary, + modify the justification and the coords of the reference point to use + "B" instead of "M". This call also returns us the coords at the left + end of the baseline of normal text. */ + lx = x; + ly = y; + lj = JustMB( this, esc, text, &lx, &ly, upx, upy, just, uxu, uyu, rxu, + ryu, &x0, &y0, method, class, status ); + +/* Initialise the horizontal and verical limits of the total bounding box. */ + alpha_lo = FLT_MAX; + alpha_hi = -FLT_MAX; + beta_lo = FLT_MAX; + beta_hi = -FLT_MAX; + +/* Tell the grf module whether or not to interpret escape sequences,and + also note if the grf module is capable of interpreting escape + sequences. */ + grfcap = GCap( this, GRF__ESC, esc, status ); + +/* Forget the horizontal position remembered by any "%h+" escape sequences + from any previous string. */ + this->hmarkx = FLT_MAX; + this->hmarky = FLT_MAX; + +/* If escape sequences are being interpreted and the string contains some + escape sequences, but the grf module cannot interpret escape sequences, + split the supplied text up into sub-strings delimited by escape sequences + and plot each sub-string individually, modifying the reference point and + graphics attributes as indicated by the escape sequences. */ + if( esc && HasEscapes( text, status ) && !grfcap ) { + +/* Take a copy of the supplied text so that we can temporarily terminate + each sub-string by poking a null (0) character into it. */ + lt = (char *) astStore( NULL, (void *) text, strlen( text ) + 1 ); + +/* Indicate that the current baseline is at its normal height. */ + rise = 0.0; + +/* Get the graphical attribute values for normal text. */ + GAttr( this, GRF__SIZE, AST__BAD, &nsize, GRF__TEXT, method, class, status ); + GAttr( this, GRF__WIDTH, AST__BAD, &nwidth, GRF__TEXT, method, class, status ); + GAttr( this, GRF__FONT, AST__BAD, &nfont, GRF__TEXT, method, class, status ); + GAttr( this, GRF__STYLE, AST__BAD, &nstyle, GRF__TEXT, method, class, status ); + GAttr( this, GRF__COLOUR, AST__BAD, &ncol, GRF__TEXT, method, class, status ); + +/* The "concatenation point" (cx,cy) is the point where the normal baseline + crosses the left hand edge of the substring bounding box. Initialise + this to the left edge of the first substring. */ + cx = x0; + cy = y0; + +/* Loop round the whole string, drawing each sub-string. */ + a = lt; + while( *a && astOK ) { + +/* Examine the start of the remaining string and note if it begins with + an escape sequence. If so, the type and value of the escape sequnece + is returned. In either case the number of characters to the next + delimiter is returned. */ + got_esc = astFindEscape( a, &estype, &esval, &nc ); + +/* If the string starts with an escaped percent sign, modify things so that + we can draw the percent sign with the normal text drawing code below. */ + if( got_esc && estype == GRF__ESPER ) { + got_esc = 0; + a++; + nc = 1; + } + +/* If the string starts with any other escape sequence, modify the graphics + attributes and concatenation point as required by the escape sequence. */ + if( got_esc ) { + InterpEscape( this, estype, (double) esval, &cx, &cy, ux, uy, + rx, ry, lj, &rise, nsize, nstyle, nwidth, ncol, + nfont, method, class, status ); + +/* If the remaining string starts with normal text, draw it. */ + } else { + +/* Temporarily terminate the sub-string which ends with the next escape + sequence. */ + cc = a[ nc ]; + a[ nc ] = 0; + +/* We now have to decide on the reference point for this sub-string. If + the justification is "BL" then the reference point is just the current + concatenation point. */ + if( lj[ 0 ] == 'B' && lj[ 1 ] == 'L' ) { + lx = cx; + ly = cy; + +/* Otherwise, the reference point is offset from the concatenation point. + It would be simpler to draw all substrings with "BL" justification but + this causes problems with some grf modules (such as GAIA) which zoom + the display by modifying the position of text strings without also + modifying the size of text strings. Using the correct reference point + for all sub-strings minimises the drift which occurs when such a grf + modules zooms the display. */ + } else { + +/* Find the width and height of this substring, and the distance between the + bottom of the bounding box and the baseline (the drop). We do this + by calling this function recursively, using "BL" justification to + avoid infinite recursion. */ + +/* Forget the horizontal position remembered by any "%h+" escape sequences + from any previous string. Save and re-instate the position of the + horizontal mark since the call to DrawText may change it. */ + hmx = this->hmarkx; + hmy = this->hmarky; + + DrawText( this, 0, esc, a, cx, cy, "BL", upx, upy, txbn, tybn, + &tdrop, method, class, status ); + + this->hmarkx = hmx; + this->hmarky = hmy; + + dx = txbn[ 0 ] - txbn[ 3 ]; + dy = tybn[ 0 ] - tybn[ 3 ]; + width = sqrt( dx*dx + dy*dy ); + + dx = txbn[ 0 ] - txbn[ 1 ]; + dy = tybn[ 0 ] - tybn[ 1 ]; + height = sqrt( dx*dx + dy*dy ); + +/* First move right from the concatenation point by a fraction of the width + of the substring (0.5 for "C" and 1.0 for "R"). */ + if( lj[ 1 ] == 'C' ) { + width *= 0.5; + } else if( lj[ 1 ] != 'R' ) { + width = 0; + } + lx = cx + rxu*width; + ly = cy + ryu*width; + +/* Now move vertically by an amount which produes the requested vertical + justification. */ + if( lj[ 0 ] == 'T' ) { + height -= tdrop; + lx += height*uxu; + ly += height*uyu; + + } else if( lj[ 0 ] == 'C' ) { + height = 0.5*height - tdrop; + lx += height*uxu; + ly += height*uyu; + + } else if( lj[ 0 ] == 'M' ) { + lx -= tdrop*uxu; + ly -= tdrop*uyu; + } + } + +/* Draw it, and then find its real bounding box (i.e. using the correct + reference position found above). */ + if( ink ) GText( this, a, lx, ly, lj, upx, upy, method, class, status ); + GTxExt( this, a, lx, ly, lj, upx, upy, txbn, tybn, method, class, status ); + +/* Re-instate the orignal value of the terminator character.*/ + a[ nc ] = cc; + +/* Move the concatenation point to the right (i.e. in the direction of the text + baseline) by an amount equal to the width of the bounding box. Also + update the total bounding box limits.*/ + UpdateConcat( txbn, tybn, ux, uy, rx, ry, &cx, &cy, + x0, y0, &alpha_lo, &alpha_hi, &beta_lo, &beta_hi, status ); + } + +/* Move on to the next character. */ + a += nc; + } + +/* Free resources. */ + lt = astFree( lt ); + +/* Reset all attributes to their normal values. */ + GAttr( this, GRF__SIZE, nsize, NULL, GRF__TEXT, method, class, status ); + GAttr( this, GRF__WIDTH, nwidth, NULL, GRF__TEXT, method, class, status ); + GAttr( this, GRF__COLOUR, ncol, NULL, GRF__TEXT, method, class, status ); + GAttr( this, GRF__FONT, nfont, NULL, GRF__TEXT, method, class, status ); + GAttr( this, GRF__STYLE, nstyle, NULL, GRF__TEXT, method, class, status ); + +/* If any escape sequences can be interpreted by the grf module, just pass + the text string on to the grf module. */ + } else { + if( ink ) GText( this, text, lx, ly, lj, upx, upy, method, class, status ); + GTxExt( this, text, lx, ly, lj, upx, upy, txbn, tybn, method, class, status ); + +/* The corners in the bounding box returned by GTxExt are in no + particular order. But this function is contracted to return them + in a specified order. So we use UpdateConcat to find the verical and + horizontal limits of the box in a form which can be used to produce + the correct order. UpdateConcat will also update the concatenation point, + but that is irrelevant in this context. */ + UpdateConcat( txbn, tybn, ux, uy, rx, ry, &lx, &ly, x0, y0, &alpha_lo, + &alpha_hi, &beta_lo, &beta_hi, status ); + } + +/* Return the total bounding box,in the order bottom left, topleft, top + right, bottom right. */ + xbn[ 0 ] = x0 + alpha_lo*ux + beta_lo*rx; + ybn[ 0 ] = y0 + alpha_lo*uy + beta_lo*ry; + + xbn[ 1 ] = x0 + alpha_hi*ux + beta_lo*rx; + ybn[ 1 ] = y0 + alpha_hi*uy + beta_lo*ry; + + xbn[ 2 ] = x0 + alpha_hi*ux + beta_hi*rx; + ybn[ 2 ] = y0 + alpha_hi*uy + beta_hi*ry; + + xbn[ 3 ] = x0 + alpha_lo*ux + beta_hi*rx; + ybn[ 3 ] = y0 + alpha_lo*uy + beta_hi*ry; + +/* Return the drop. */ + if( drop ) *drop = -alpha_lo*ulen; + +/* Free memory.*/ + lj = astFree( (void *) lj ); + +/* If OK, update the box containing all drawn graphics primitives. */ + if( ink && astOK && !Boxp_freeze ) { + for( i = 0; i < 4; i++ ){ + Boxp_lbnd[ 0 ] = astMIN( xbn[ i ], Boxp_lbnd[ 0 ] ); + Boxp_ubnd[ 0 ] = astMAX( xbn[ i ], Boxp_ubnd[ 0 ] ); + Boxp_lbnd[ 1 ] = astMIN( ybn[ i ], Boxp_lbnd[ 1 ] ); + Boxp_ubnd[ 1 ] = astMAX( ybn[ i ], Boxp_ubnd[ 1 ] ); + } + } +} + +static void DrawTicks( AstPlot *this, TickInfo **grid, int drawgrid, + double *labelat, double *gap, const char *method, + const char *class, int *status ){ +/* +* +* Name: +* DrawTicks + +* Purpose: +* Draw tick marks for a 2-D annotated coordinate grid. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void DrawTicks( AstPlot *this, TickInfo **grid, int drawgrid, +* double *labelat, double *gap, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function draws major and minor tick marks. It uses a different +* technique depending on whether the tick marks are to be put along the +* edges of the plotting area, or along a curve through the middle of the +* plotting area. The physical axis values at which to put tick marks +* are supplied in parameter "grid". +* +* If the ticks are placed on the edges of the plotting area, The +* EdgeCrossings function is used to find all points along the edge which +* have a physical axis value correspoinding to a tick value (there can in +* general be more than one point on an edge with a given physical axis +* value). Ticks are put at all such crossings. +* +* If ticks are placed within the plotting area, then they are put +* along a curve defined by the "other axis" values supplied in +* parameter "labelat". + +* Parameters: +* this +* A pointer to the Plot. +* grid +* A pointer to an array of two TickInfo pointers (one for each axis), +* each pointing to a TickInfo structure holding information about +* tick marks on the axis. See function GridLines. +* drawgrid +* If non-zero, then a grid of curves has been drawn to mark the +* major axis values. +* labelat +* A pointer to a 2 element array in holding the constant axis +* values at which tick marks are to be put. Element 0 should hold +* the axis 1 value at which tick marks for axis 0 are placed. Element +* 1 should hold the axis 0 value at which tick marks for axis +* 1 are placed. If ticks are to be placed round the edges of the +* plotting zone instead of within the plotting zone, then values of +* AST__BAD should be supplied. +* gap +* Pointer to array of two values holding the gap between major +* tick marks on the two axes. This will be the difference between, +* or the ratio of, adjacent tick mark values, depending on the +* setting of the LogTicks attribute. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Notes: +* - This function assumes the current Frame of the Plot is 2 +* dimensional, and it should not be called if this is not the case. +*/ + +/* Local Variables: */ + AstFrame *frame; /* Pointer to current Frame in Plot */ + AstMapping *mapping; /* Pointer to graphics->physical Mapping */ + AstPointSet *pset1; /* Pointer to PointSet holding physical coords. */ + AstPointSet *pset2; /* Pointer to PointSet holding graphics coords. */ + AstPointSet *pset3; /* Pointer to PointSet holding clipped graphics coords. */ + EdgeCrossingsStatics *ecstatics = NULL; /* For static data structure */ + TickInfo *info; /* Pointer to the TickInfo for the current axis */ + double *ptr1[2]; /* Pointer to physical data */ + double **ptr2; /* Pointer to graphics data */ + double **ptr3; /* Pointer to clipped graphics data */ + double *a; /* Pointer to next current axis value */ + double *b; /* Pointer to next other axis value */ + double *value; /* Current tick value */ + double *x; /* Pointer to next X value */ + double *xc; /* Pointer to next clipped X value */ + double *y; /* Pointer to next Y value */ + double *yc; /* Pointer to next clipped Y value */ + double a0; /* Physical axis value at base of tick */ + double axmax; /* Upper axis limit */ + double axmin; /* Lower axis limit */ + double delta1; /* Increment between minor ticks above major tick */ + double delta2; /* Increment between minor ticks below major tick */ + double diff; /* Difference between adjacent major ticks */ + double dl2; /* Squared increment between points */ + double dl2_limit; /* Minimum usable squared increment between points */ + double dl; /* Increment between points */ + double dx; /* X component of increment along tick mark */ + double dy; /* Y component of increment along tick mark */ + double ex; /* X component of increment between points */ + double ey; /* Y component of increment between points */ + double lblat2; /* Other axis value part way up each tick */ + double lblat; /* Other axis value at base of each tick */ + double mindim; /* Shortest dimension of plotting area */ + double minval; /* Current axis value at next minor tick */ + double mjsign; /* Sign of the major tick mark length */ + double mjtklen; /* Length of major tick marks */ + double mnsign; /* Sign of the minor tick mark length */ + double mntklen; /* Length of minor tick marks */ + double ux; /* X component of unit vector along tick mark */ + double uy; /* Y component of unit vector along tick mark */ + double val; /* Major axis value */ + double x0; /* X at base of tick */ + double x1; /* X at end of tick */ + double x2; /* Clipped X at base of tick */ + double y0; /* Y at base of tick */ + double y1; /* Y at end of tick */ + double y2; /* Clipped Y at base of tick */ + int *majflag; /* Pointer to next major/minor flag */ + int *majflags; /* Pointer to aray of major/minor flags */ + int axis; /* Current axis index */ + int ed; /* Doing a secondary edge? */ + int edge; /* Index of edge being ticked */ + int first; /* Is this the first tick to be drawn? */ + int gelid; /* ID for next graphical element to be drawn */ + int i; /* Minor tick mark index */ + int logticks; /* Are major tick marks logarithmically spaced? */ + int minhi; /* Highest minor tick mark index */ + int minlo; /* Lowest minor tick mark index */ + int nedge; /* No. of edges to be ticked for each axis */ + int nel; /* Actual number of tick marks to draw */ + int ntot; /* Maximum number of tick marks */ + int tick; /* Tick index */ + int lasttick; /* Index of last major tick mark */ + +/* Check the global status. */ + if( !astOK ) return; + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + a = NULL; + delta1 = 0.0; + delta2 = 0.0; + lblat2 = 0.0; + uy = 0.0; + logticks = 0; + +/* Get the minimum dimension of the plotting ares. */ + mindim = astMIN( this->xhi - this->xlo, this->yhi - this->ylo ); + +/* Information about the drawn tick marks is saved in the Plot structure. + Reset this information now so that we are ready to store information + about the new ticks that will be drawn by this function invocation. */ + SaveTick( this, -1, 0.0, 0.0, 0, status ); + +/* If ticks are to be put round the edges of the plotting area... */ +/* ============================================================== */ + if( labelat[ 0 ] == AST__BAD || labelat[ 1 ] == AST__BAD ){ + +/* Store the number of edges to be ticked for each axis. */ + nedge = astGetTickAll( this )? 2 : 1; + +/* Do each required edge. */ + for( ed = 0; ed < nedge; ed++ ){ + +/* Initialize the id value for graphical element being drawn. */ + gelid = AST__TICKS1_ID; + +/* Do each axis. */ + for( axis = 0; axis < 2; axis++ ){ + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + astGrfAttrs( this, gelid, 1, GRF__LINE, method, class ); + +/* Store the length in graphics coordinates of major tick marks for this + axis. Use a default of zero if a grid has been drawn. */ + if( astTestMajTickLen( this, axis ) || !drawgrid ){ + mjtklen = astGetMajTickLen( this, axis )*mindim; + } else { + mjtklen = 0.0; + } + +/* Store the length in graphics coordinates of minor tick marks. */ + mntklen = astGetMinTickLen( this, axis )*mindim; + +/* Get the edge to be labelled with the axis values. Edge 0 is the left hand + edge. Edge 1 is the top edge. Edge 2 is the right-hand edge. Edge 3 is + the bottom edge. */ + edge = ( astGetEdge( this, axis ) + ed*2 ) % 4; + if( edge < 0 ) edge = -edge; + +/* Store a pointer to the structure containing information describing the + positions of the major tick marks along this axis. */ + info = grid[ axis ]; + +/* Store a pointer to the axis value at the first major tick mark. */ + value = info->ticks; + +/* Minor tick marks are drawn on both sides of each major tick mark. They + are identified by an index number relative to major tick mark at zero. + Store the indices of the first and last minor tick marks. */ + minlo = ( 1 - info->nminor )/2; + minhi = info->nminor/2; + +/* If major ticks are linear, store the difference between minor tick marks. + This value will be the same for all major ticks. */ + logticks = astGetLogTicks( this, axis ); + if( !logticks ) { + delta1 = gap[ axis ]/(double)info->nminor; + delta2 = delta1; + } + +/* Loop round until all ticks have been done. */ + for( tick = 0; tick < info->nmajor; tick++ ){ + +/* Draw tick marks at all occurrences of the current major tick value on + the selected edge of the plotting area. */ + Ticker( this, edge, axis, *value, gap, mjtklen, + 1, ( ed == 0 ), &ecstatics, method, class, status ); + +/* If minor tick mark values were not supplied, calculate them as even + intervals between the major tick values. */ + if( !info->minticks ) { + +/* If major ticks are logarithmic, store the difference between minor tick + marks. This value will be different for each major tick. Also, since + the minor ticks are drawn on either side of the major tick, the minor + tick spacing above the major tick will be different to that below the + minor tick when using logarathmic ticks. "delta1" is the minor gap + above the major value, and "delta2" is the minor gap below the major + value. */ + if( logticks ) { + delta1 = (*value) * ( gap[ axis ] - 1.0 )/ + (double)info->nminor; + delta2 = delta1 / gap[ axis ]; + } + +/* Extra minor tick marks are drawn below the first major tick mark and + above the last major tick mark to fill in any gaps caused by axis + limits being exceeded. */ + if( tick == 0 ) { + minlo = 1 - info->nminor; + } if( tick == 1 ) { + minlo = ( 1 - info->nminor )/2; + } else if( tick == info->nmajor - 1 ) { + minhi = info->nminor - 1; + } + +/* Store the axis value at the first minor tick mark. */ + minval = *value + minlo*delta2; + +/* Loop round all the minor tick marks, storing the physical coordinates + defining the tick mark. */ + for( i = minlo; i <= minhi; i++ ){ + +/* Draw tick marks at all occurrences of the current minor tick value on + the selected edge of the plotting area. Do not do the minor tick mark + with index zero, since this corresponds to the position of the major + tick mark. */ + if( i ) Ticker( this, edge, axis, minval, gap, mntklen, + 0, ( ed == 0 ), &ecstatics, method, class, status ); + +/* Get the axis value at the next minor tick mark. */ + minval += ( i < 0 ) ? delta2 : delta1; + } + } + +/* Point to the next major tick value. */ + value++; + + } + +/* If minor tick mark values have been supplied, used them. */ + if( info->minticks ) { + value = info->minticks; + for( tick = 0; tick < info->nminor; tick++, value++ ){ + Ticker( this, edge, axis, *value, gap, mntklen, 0, + ( ed == 0 ), &ecstatics, method, class, status ); + } + } + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, gelid, 0, GRF__LINE, method, class ); + +/* Set up the id for the next graphical element to be drawn. */ + gelid = AST__TICKS2_ID; + } + } + +/* Free the static resources allocated within EdgeCrossings (called + by Ticker). */ + (void) EdgeCrossings( NULL, 0, 0, 0.0, NULL, NULL, &ecstatics, method, + class, status ); + +/* If ticks are to put within the interior of the plotting area... */ +/* ============================================================== */ + } else { + +/* Get the mapping from base Frame (graphics coords) to current Frame + (physical coords). */ + mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); + +/* Get the current Frame from the Plot. */ + frame = astGetFrame( this, AST__CURRENT ); + +/* Initialize the id value for graphical element being drawn. */ + gelid = AST__TICKS1_ID; + +/* Do each axis. */ + for( axis = 0; axis < 2; axis++ ){ + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + astGrfAttrs( this, gelid, 1, GRF__LINE, method, class ); + +/* Store the length in graphics coordinates of major tick marks for this + axis. Use a default of zero if a grid has been drawn. */ + if( astTestMajTickLen( this, axis ) || !drawgrid ){ + mjtklen = astGetMajTickLen( this, axis )*mindim; + } else { + mjtklen = 0.0; + } + +/* Store the length in graphics coordinates of minor tick marks. */ + mntklen = astGetMinTickLen( this, axis )*mindim; + +/* Indicate that the tick mark lengths should not be negatated. */ + mjsign = 1.0; + mnsign = 1.0; + +/* Store the smallest squared distance in graphics coordinates which + can reliably be used to determine the direction of a tick mark. */ + dl2_limit = 0.0001*mindim; + dl2_limit *= dl2_limit; + +/* Store a pointer to the structure containing information describing the + positions of the major tick marks along this axis. */ + info = grid[ axis ]; + +/* Store a pointer to the axis value at the first major tick mark. */ + value = info->ticks; + +/* Get the maximum number of tick marks to be drawn on this axis. */ + ntot = 0; + ntot = info->nmajor; + if( info->minticks ) { + ntot += info->nmajor + info->nminor; + } else { + ntot += ( info->nmajor + 1 )*( info->nminor - 1 ); + } + +/* Pass on to the next axis if no ticks are to be drawn. */ + if( ntot ) { + +/* Allocate memory to hold the physical coordinates defining all the + required tick marks. Each tick mark is defined by 2 points. */ + ptr1[ 0 ] = (double *) astMalloc( sizeof(double)*(size_t)(2*ntot) ); + ptr1[ 1 ] = (double *) astMalloc( sizeof(double)*(size_t)(2*ntot) ); + +/* Allocate memory to hold a set of flags indicating whether each tick + mark is minor or major. */ + majflags = (int *) astMalloc( sizeof(int)*(size_t)ntot ); + +/* Check the pointers can be used. */ + if( astOK ){ + +/* If the tick values have been supplied using astSetTickValues, just + copy them into the above arrays. */ + if( info->minticks ) { + + a = ptr1[ axis ]; + b = ptr1[ 1 - axis ]; + majflag = majflags; + + for( tick = 0; tick <= info->nmajor; tick++ ){ + + val = info->ticks[ tick ]; + if( logticks ) { + diff = val * ( gap[ axis ] - 1.0 ); + lblat2 = labelat[ axis ] + 0.2*diff; + } else { + lblat2 = labelat[ axis ] + 0.2*gap[ 1 - axis ]; + } + + *(a++) = val; + *(b++) = labelat[ axis ]; + *(a++) = val; + *(b++) = lblat2; + *(majflag++) = 1; + } + + for( tick = 0; tick <= info->nminor; tick++ ){ + + val = info->minticks[ tick ]; + if( logticks ) { + diff = val * ( gap[ axis ] - 1.0 ); + lblat2 = labelat[ axis ] + 0.2*diff; + } else { + lblat2 = labelat[ axis ] + 0.2*gap[ 1 - axis ]; + } + + *(a++) = val; + *(b++) = labelat[ axis ]; + *(a++) = val; + *(b++) = lblat2; + *(majflag++) = 0; + } + +/* If the tick values were not supplied using astSetTickValues, then we + need to calculate the minor tick positions explicitly. */ + } else { + +/* Store pointers to the next point on each axis. "a" always refers to the + current axis. Also store the value on the other axis at which the tick + marks starts, and another value on the other axis which is used to + defined the tick mark directions. */ + a = ptr1[ axis ]; + b = ptr1[ 1 - axis ]; + majflag = majflags; + lblat = labelat[ axis ]; + +/* Store another value on the other axis which is used to defined the tick + mark directions, and the difference between minor tick marks. For + linearly spaced tick marks these values will be the same for all major + ticks. Minor ticks are always drawn above the correponding major + value (i.e. minlo == 1 ) and so we do not need to set delta2. */ + logticks = astGetLogTicks( this, axis ); + if( !logticks ) { + lblat2 = labelat[ axis ] + 0.2*gap[ 1 - axis ]; + delta1 = gap[ axis ]/(double)info->nminor; + } + +/* Store the indices of the first and last minor tick marks, relative to + a major tick mark. */ + minlo = 1; + minhi = info->nminor - 1; + +/* Get the axis limits. */ + axmin = astGetBottom( frame, axis ); + axmax = astGetTop( frame, axis ); + +/* Loop round until all ticks have been done. We include a hypothetical tick + at index -1 (i.e. one gap below the first listed tick value) in order + to get minor tick marks below the first major tick. But the + hypothetical major tick value is not included in the list of major tick + values to draw. */ + lasttick = info->nmajor - 1; + for( tick = -1; tick <= lasttick; tick++ ){ + +/* Get the major tick value. */ + if( tick == -1 ) { + if( !logticks ) { + val = (*value) - gap[ axis ]; + }else { + val = (*value)/gap[ axis ]; + } + } else { + val = *(value++); + } + +/* Now find the value on the other axis which is used to defined the tick + mark directions, and the difference between minor tick marks, in the + case of logarithmically spaced tick marks. These values will be + different for every major tick. Minor ticks are always drawn above the + correponding major value (i.e. minlo == 1 ) and so we do not need to set + delta2. */ + if( logticks ) { + diff = val * ( gap[ axis ] - 1.0 ); + lblat2 = labelat[ axis ] + 0.2*diff; + delta1 = diff / (double)info->nminor; + } + +/* If major tick marks are required, store the physical coordinates at the + start of the major tick mark, and at a point a little way up the major + tick mark. */ + if( tick > -1 ){ + *(a++) = val; + *(b++) = lblat; + *(a++) = val; + *(b++) = lblat2; + *(majflag++) = 1; + } + +/* Store the points defining the minor tick marks on either side of + this major tick mark. First store the axis value at the first minor + tick mark. */ + minval = val + minlo*delta1; + +/* Loop round all the minor tick marks, storing the physical coordinates + defining the tick mark. */ + for( i = minlo; i <= minhi; i++ ){ + +/* Do not do the minor tick mark with index zero, since this corresponds + to the position of the major tick mark. Do not do any minor ticks that + are outside the axis range. */ + if( i && minval >= axmin && minval <= axmax ){ + *(a++) = minval; + *(b++) = lblat; + *(a++) = minval; + *(b++) = lblat2; + *(majflag++) = 0; + } + +/* Get the axis value at the next minor tick mark. */ + minval += delta1; + } + } + } + } + +/* Adjust the size of the arrays to exclude any unused space. */ + nel = a - ptr1[axis]; + ptr1[axis] = (double *) astRealloc( (void *) ptr1[axis], + sizeof(double)*nel ); + ptr1[1-axis] = (double *) astRealloc( (void *) ptr1[1-axis], + sizeof(double)*nel ); + +/* Create a pointset holding these coordinates. */ + pset1 = astPointSet( nel, 2, "", status ); + astSetPoints( pset1, ptr1 ); + +/* Transform these physical coordinates into graphics coordinates, without + doing any clipping (this is so that tick marks are still drawn even if + they extend into the area containing clipped physical coordinates). */ + pset2 = astTransform( mapping, pset1, 0, NULL ); + ptr2 = astGetPoints( pset2 ); + +/* Transform them again this time with clipping. */ + pset3 = Trans( this, NULL, mapping, pset1, 0, NULL, 0, method, class, status ); + ptr3 = astGetPoints( pset3 ); + +/* Check the pointers can be used.*/ + if( astOK ){ + +/* Store pointers to the next point on each axis. */ + a = ptr1[ axis ]; + + x = ptr2[ 0 ]; + y = ptr2[ 1 ]; + + xc = ptr3[ 0 ]; + yc = ptr3[ 1 ]; + + majflag = majflags; + +/* Loop round all ticks (major and minor). */ + ux = AST__BAD; + first = 1; + for( tick = 0; tick < nel/2; tick++ ){ + +/* Store the physical axis value at the base of the tick mark (skip over + the physical axis value at the point up the tick mark). */ + a0 = *(a++); + a++; + +/* Store the x and y coordinates at the base of the tick mark. */ + x0 = *(x++); + y0 = *(y++); + +/* Store the x and y coordinates at a point up the tick mark. */ + x1 = *(x++); + y1 = *(y++); + +/* Store the clipped x and y coordinates at the base of the tick mark. */ + x2 = *(xc++); + y2 = *(yc++); + +/* Skip over the clipped x and y coordinates at the point up the tick mark. */ + xc++; + yc++; + +/* Check they are all valid, and that the start of the tick mark is within + the plotting area. */ + if( x0 != AST__BAD && y0 != AST__BAD && + x1 != AST__BAD && y1 != AST__BAD && + x2 != AST__BAD && y2 != AST__BAD && + x0 <= this->xhi && x0 >= this->xlo && + y0 <= this->yhi && y0 >= this->ylo ){ + +/* Get the increments in X and Y beyween the two points, and the squared + distance between the two points. */ + dx = x1 - x0; + dy = y1 - y0; + dl2 = dx*dx + dy*dy; + +/* Check the two points are not co-incident. */ + if( dl2 > dl2_limit ){ + +/* Store the distance between the two points. */ + dl = sqrt( dl2 ); + +/* If this is the first tick to be drawn on this axis, decide which + direction to draw the tick mark so that they will appear on the right + hand side of the axis as seen by someone moving along the axis in the + positive direction (the numerical labels are also drawn on the same + side). */ + if( first ){ + first = 0; + +/* If the next tick mark is not defined, make an arbitrary decision by + leaving the sign of the tick mark length unchanged. */ + if( tick + 1 < nel/2 && + *x != AST__BAD && *y != AST__BAD && + a0 != AST__BAD && *a != AST__BAD ){ + +/* Form the vector joining this tick mark to the next. */ + ex = *x - x0; + ey = *y - y0; + +/* Ensure this vector is in the positive direction of the axis. */ + if( *a < a0 ) { + ex = -ex; + ey = -ey; + } + +/* If a positive tick mark length would put the marks on the wrong side, + negate the tick mark length. */ + if( ex*dy > ey*dx ){ + mjsign = -1.0; + mnsign = -1.0; + } + } + } + +/* Store the unit vector in the direction of the tick mark. This is used + as the default vector for the next tick mark if the direction of the + next tick mark is indeterminate. */ + ux = dx/dl; + uy = dy/dl; + } + +/* Only draw this tickmark if its direction is known. */ + if( ux != AST__BAD ) { + +/* Get the position of the end of the tick mark. The length of the tick + mark depends on whether it is a major or minor tick mark. */ + if( *majflag ){ + x1 = x0 + mjsign*mjtklen*ux; + y1 = y0 + mjsign*mjtklen*uy; + } else { + x1 = x0 + mnsign*mntklen*ux; + y1 = y0 + mnsign*mntklen*uy; + } + +/* Save and draw the tick mark. */ + SaveTick( this, axis, x0, y0, *majflag, status ); + if( x0 != x1 || y0 != y1 ) { + Bpoly( this, (float) x0, (float) y0, status ); + Apoly( this, (float) x1, (float) y1, status ); + Opoly( this, status ); + } + } + } + +/* Point to the next major/minor flag. */ + majflag++; + } + } + +/* Free the memory holding the physical coordinates. */ + ptr1[ 0 ] = (double *) astFree( ( void *) ptr1[ 0 ] ); + ptr1[ 1 ] = (double *) astFree( ( void *) ptr1[ 1 ] ); + majflags = (int *) astFree( (void *) majflags ); + +/* Annul the PointSets. */ + pset1 = astAnnul( pset1 ); + pset2 = astAnnul( pset2 ); + pset3 = astAnnul( pset3 ); + } + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, gelid, 0, GRF__LINE, method, class ); + +/* Set up the id for the next graphical element to be drawn. */ + gelid = AST__TICKS2_ID; + } + +/* Annul the pointers to the Mapping and Frame. */ + mapping = astAnnul( mapping ); + frame = astAnnul( frame ); + + } + +/* Return. */ + return; + +} + +static void EBuf( AstPlot *this, int *status ) { +/* +*++ +* Name: +c astEBuf +f AST_EBUF + +* Purpose: +* End the current graphical buffering context. + +* Type: +* Public function. + +* Synopsis: +c #include "plot.h" +c void astEBuf( AstPlot *this ) +f CALL AST_EBUF( THIS STATUS ) + +* Class Membership: +* Plot member function. + +* Description: +c This function +f This routine +* ends the current graphics buffering context. It should match a +* corresponding call to the +c astBBuf function. +f AST_EBUF routine. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +* - The nature of the buffering is determined by the underlying +* graphics system (as defined by the current grf module). Each call +c to this function +f to this routine +* simply invokes the astGEBuf function in the grf module. + +*-- +*/ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Invoke the active GRF EBuf function. */ + GEBuf( this, "astEBuf", astGetClass( this ), status ); +} + +static int EdgeLabels( AstPlot *this, int ink, TickInfo **grid, + AstPlotCurveData **cdata, int force, const char *method, + const char *class, int *status ){ +/* +* +* Name: +* EdgeLabels + +* Purpose: +* Attempts to display labels for the major tick values around the edges +* of the plotting area. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int EdgeLabels( AstPlot *this, int ink, TickInfo **grid, +* AstPlotCurveData **cdata, int force, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function determines how many major tick value labels could be +* placed on the specified edges of the plotting area, and then if +* requested, and if sufficient such labels are found (more than 3 on +* each axis), they are drawn. To place a label on an edge, the curve +* defining the major tick value must cross the edge at a reasonably +* angle (at least 3 degrees). Labels are not drawn which would overlap +* other, previously drawn, labels. A flag is returned indicating if +* edge labels were (or could be) drawn. + +* Parameters: +* this +* A pointer to the Plot. +* ink +* If zero, then no labels are drawn, but the decision whether or +* not to draw them is still made and indicated in the returned function +* value. +* grid +* A pointer to an array of two TickInfo pointers (one for each axis), +* each pointing to a TickInfo structure holding information about +* tick marks on the axis. See function GridLines. +* cdata +* A pointer to an array of two AstPlotCurveData pointers (one for each axis), +* each pointing to an array of AstPlotCurveData structure (one for each +* major tick value on the axis), holding information about breaks +* in the curves drawn to mark the major tick values. See function +* DrawGrid. +* force +* If non-zero, then an attempt is made to draw edge labels even if +* it looks like insufficient edge labels can be produced. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* If edge labels were drawn, 1 is returned. Otherwise 0 is returned. + +* Notes: +* - Zero is returned if an error has already occurred. +*/ + + +/* Local Variables: */ + AstFrame *frame; /* Pointer to current Frame */ + AstPlotCurveData *cdt; /* Pointer to the AstPlotCurveData for the next tick */ + LabelList *labellist; /* Pointer to a ingle list of labels to be plotted */ + LabelList *ll; /* Pointer to next label to be plotted */ + LabelList *llist[2]; /* Pointers to both lists of labels to be plotted */ + TickInfo *info; /* Pointer to the TickInfo for the current axis */ + const char *just[ 2 ]; /* Justification string */ + const char *text; /* Pointer to label text */ + double edgeval; /* Axis value at the labelled edge */ + double mindim; /* Minimum dimension of the plotting area */ + double oppval; /* Axis value on the edge opposite to the labels */ + double tol; /* Max. distance between a break and the edge */ + double txtgap; /* Absolute gap between labels and edges */ + float *box; /* Pointer to array of label bounding boxes */ + float *vxbrk; /* X component of unit vector at current break */ + float *vybrk; /* Y component of unit vector at current break */ + float *xbrk; /* X coord. of current break */ + float *ybrk; /* Y coord. of current break */ + float xref; /* X coordinate at label's reference position */ + float yref; /* Y coordinate at label's reference position */ + int axis; /* Current axis index */ + int brk; /* Current break index */ + int edge; /* The edge to be labelled */ + int edgeax; /* Index of axis parallel to the labelled edge */ + int edgelabs; /* Can edge labels be produced? */ + int esc; /* INterpret escape sequences? */ + int gelid; /* ID for next graphical element to be drawn */ + int ii; /* Index into existing labels */ + int maxlab; /* Number of distinct edge labels */ + int medge[2]; /* No. of distinct edge labels for each axis */ + int naxlab; /* Number of edge labels */ + int near; /* Draw a label on the near edge? */ + int nedge[2]; /* No. of edge labels for each axis */ + int ok; /* Can the current tick mark be labelled on the edge? */ + int labfound; /* Label value has already been used? */ + int tick; /* Tick index */ + int upright; /* Draw all labels upright? */ + +/* Check the global status. */ + if( !astOK ) return 0; + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + xref = 0.0; + yref = 0.0; + +/* See if escape sequences in text strings are to be interpreted. */ + esc = astGetEscape( this ); + +/* Initialise the returned flag to indicate that edge labels cannot be + produced. */ + edgelabs = 0; + +/* Get the minimum dimension of the plotting ares. */ + mindim = astMIN( this->xhi - this->xlo, this->yhi - this->ylo ); + +/* Set up the tolerance for curve breaks occuring on an edge of + the plotting zone. */ + tol = 0.005*mindim; + +/* First, we get a list of all the labels which can be produced on each + axis. The list includes the labels reference position in graphics + coordinates, and the index of the major tick value which it + represents. We do not yet know whether enough of the grid lines cross + the required edge to make it feasable to use edge labelling, so we do + not yet draw the labels. + =====================================================================*/ + +/* Initialise pointers to arrays of structures holding information + about the labels which can be draw round the edge for both axes. */ + llist[ 0 ] = NULL; + llist[ 1 ] = NULL; + +/* Indicate that no labels can yet be drawn on either axis. */ + nedge[ 0 ] = 0; + nedge[ 1 ] = 0; + +/* The "nedge" array counts the number of labels on each edge. But some + of these labels may be for the same tick mark (if the tick mark curve has + more than 1 intersection with the edge). The "medge" array counts the + number of *distinct* tick mark labels (i.e. the number of tick mark + values which have 1 or more interesections with the edge). */ + medge[ 0 ] = 0; + medge[ 1 ] = 0; + +/* For each axis, identify the the usable edge labels. */ + for( axis = 0; axis < 2; axis++ ){ + +/* See if labels for this axis are to be drawn upright. */ + if( astTestLabelUp( this, axis ) ) { + upright = astGetLabelUp( this, axis ); + } else { + upright = 1; + } + +/* Store the required gap between the label text and the axis. */ + txtgap = astGetNumLabGap( this, axis )*mindim; + +/* Get the edge to be labelled with the axis values. Edge 0 is the left hand + edge. Edge 1 is the top edge. Edge 2 is the right-hand edge. Edge 3 is + the bottom edge. */ + edge = astGetEdge( this, axis ) % 4; + if( edge < 0 ) edge = -edge; + +/* If edge labels for the current axis are to go on the left hand edge of + the plotting area... */ + if( edge == 0 ){ + +/* Choose the justification based on the sign of the text gap. */ + if( !upright ) { + just[ axis ] = "BC"; + } else if( txtgap > 0.0 ){ + just[ axis ] = "CR"; + } else if( txtgap < 0.0 ){ + just[ axis ] = "CL"; + } else { + just[ axis ] = "CC"; + } + +/* Store the constant X axis value at the edge being labelled. Also store + the X value to use for the reference position for all labels. Take into + account whether or not the X axis is displayed reversed (i.e. with high + X values at the left hand side of the screen ). */ + if( !this->xrev ){ + edgeval = this->xlo; + oppval = this->xhi; + xref = (float)( edgeval - txtgap ); + } else { + edgeval = this->xhi; + oppval = this->xlo; + xref = (float)( edgeval + txtgap ); + } + +/* Indicate that the "edgeval" value refers to axis 1 (the X axis). */ + edgeax = 1; + +/* Do the same if the labels are to go on the top edge. */ + } else if( edge == 1 ){ + if( txtgap > 0.0 ){ + just[ axis ] = "BC"; + } else if( txtgap < 0.0 ){ + just[ axis ] = "TC"; + } else { + just[ axis ] = "CC"; + } + + if( !this->yrev ){ + edgeval = this->yhi; + oppval = this->ylo; + yref = (float)( edgeval + txtgap ); + } else { + edgeval = this->ylo; + oppval = this->yhi; + yref = (float)( edgeval - txtgap ); + } + + edgeax = 0; + +/* Do the same if the labels are to go on the right-hand edge. */ + } else if( edge == 2 ){ + + if( !upright ) { + just[ axis ] = "BC"; + } else if( txtgap > 0.0 ){ + just[ axis ] = "CL"; + } else if( txtgap < 0.0 ){ + just[ axis ] = "CR"; + } else { + just[ axis ] = "CC"; + } + + if( !this->xrev ){ + edgeval = this->xhi; + oppval = this->xlo; + xref = (float)( edgeval + txtgap ); + } else { + edgeval = this->xlo; + oppval = this->xhi; + xref = (float)( edgeval - txtgap ); + } + + edgeax = 1; + +/* Do the same if the labels are to go on the bottom edge. */ + } else { + if( txtgap > 0.0 ){ + just[ axis ] = "TC"; + } else if( txtgap < 0.0 ){ + just[ axis ] = "BC"; + } else { + just[ axis ] = "CC"; + } + + if( !this->yrev ){ + edgeval = this->ylo; + oppval = this->yhi; + yref = (float)( edgeval - txtgap ); + } else { + edgeval = this->yhi; + oppval = this->ylo; + yref = (float)( edgeval + txtgap ); + } + + edgeax = 0; + + } + +/* Get a pointer to the structure containing information describing the + positions of the major tick marks along this axis. */ + info = grid[ axis ]; + +/* Get a pointer to the structure containing information describing the + breaks in the curve which is parallel to the other axis and passes + through the first major tick mark. */ + cdt = cdata[ axis ]; + +/* Initialise the pointer to the list of text strings to be drawn. */ + labellist = NULL; + +/* Initialise the number of labels which can be placed on the near edge of + the plotting zone (some of which may be the same). */ + naxlab = 0; + +/* Initialise the number of distinct labelled tick mark values. */ + maxlab = 0; + +/* Loop round each of the major tick marks on the current axis. */ + for( tick = 0; cdt && info && tick < info->nmajor; tick++ ){ + +/* Store pointers to the values giving the position and unit direction + vector of the curve at the first break. */ + xbrk = cdt->xbrk; + ybrk = cdt->ybrk; + vxbrk = cdt->vxbrk; + vybrk = cdt->vybrk; + +/* Loop round each of the breaks in the curve which passes through the + current major tick mark, and is parallel to the other axis. */ + ok = 0; + for( brk = 0; brk < cdt->nbrk; brk++ ){ + +/* A label can be produced on the near edge of the plotting zone if the + current break occurs on, or close to, the edge, and the curve is not + nearly parallel to the axis (limit is 5 degs). */ + near = ( ( edgeax == 0 && + fabs( (double) *ybrk - edgeval ) < tol && + fabs( (double) *vybrk ) > 0.09 ) || + ( edgeax == 1 && + fabs( (double) *xbrk - edgeval ) < tol && + fabs( (double) *vxbrk ) > 0.09 ) ); + +/* Get the label text. */ + if( info->labels ) { + text = (info->labels)[ tick ]; + } else { + text = NULL; + } + +/* If a label can be produced, record the information needed to draw the + label. */ + if( near && text ){ + + labellist = (LabelList *) astGrow( (void *) labellist, naxlab + 1, sizeof(LabelList) ); + if ( !astOK ) break; + + if( edgeax == 0 ){ + (labellist + naxlab)->index = (double) *xbrk; + (labellist + naxlab)->x = (double) *xbrk; + (labellist + naxlab)->y = (double) yref; + } else { + (labellist + naxlab)->index = (double) *ybrk; + (labellist + naxlab)->x = (double) xref; + (labellist + naxlab)->y = (double) *ybrk; + } + + (labellist + naxlab)->text = (char *) astStore( NULL, (void *) text, strlen(text) + 1 ); + (labellist + naxlab)->just = (char *) astStore( NULL, (void *) just[ axis ], strlen(just[ axis ]) + 1 ); + +/* The up vector depends on which edge is being labelled and whether all + labels are being drawn upright or not. */ + if( edge == 1 || edge == 3 || upright ) { + (labellist + naxlab)->upx = 0.0; + (labellist + naxlab)->upy = 1.0; + } else if( edge == 0 ) { + (labellist + naxlab)->upx = -1.0; + (labellist + naxlab)->upy = 0.0; + } else { + (labellist + naxlab)->upx = 1.0; + (labellist + naxlab)->upy = 0.0; + } + + (labellist + naxlab)->val = (info->ticks)[ tick ]; + naxlab++; + +/* If this label has not already been included in the label list, indicate + that we have found another usable label. */ + labfound = 0; + for( ii = 0; ii < naxlab-1; ii++ ) { + if( fabs( (info->ticks)[ tick ] - + (labellist + ii)->val ) < 0.2*info->gap ) { + labfound = 1; + break; + } + } + if( !labfound ) ok = 1; + + } + +/* Increment the pointers to the values giving the position and unit direction + vector of the next break. */ + xbrk++; + ybrk++; + vxbrk++; + vybrk++; + + } + +/* If an error has occurred, break out of the loop. */ + if( !astOK ) break; + +/* If one or more labels could be produced for this tick mark value, + increment the number of labeled tick marks found. */ + if( ok ) maxlab++; + +/* Get a pointer to the curve through the next major tick mark. */ + cdt++; + + } + +/* If an error has occurred, break out of the loop. */ + if( !astOK ) break; + +/* Store the number of labels for this axis, and the pointer to the + drawable labels. */ + nedge[ axis ] = naxlab; + medge[ axis ] = maxlab; + llist[ axis ] = labellist; + } + +/* We now know how many labels would be produced on each axis if edge + labelling were to be used. We also know what those labelled values are, + and where the labels would be drawn. We now take the decision as to + whether there are enough of these labels to make edge labelling + feasable. If so, we carry on and draw the labels. There need to be + at least 3 labels on each axis for linear tick spacing and 2 for log + tick spacing (or a non-zero value supplied for "force")... + ================================================================= */ + if( astOK && ( ( medge[ 0 ] > ( astGetLogTicks( this, 0 ) ? 1 : 2 ) && + medge[ 1 ] > ( astGetLogTicks( this, 1 ) ? 1 : 2 ) ) + || force ) ) { + +/* Set the returned flag to indicate that edge labelling is being used. */ + edgelabs = 1; + +/* Initialise the pointer to the memory holding the bounding boxes for + all labels (used by function Overlap). */ + box = NULL; + +/* Get a pointer to the current Frame in the Plot. */ + frame = astGetFrame( this, AST__CURRENT ); + +/* Initialize the id value for graphical element being drawn. */ + gelid = AST__NUMLAB1_ID; + +/* If required, draw the labels for each axis in turn. */ + for( axis = 0; axis < 2 && ink; axis++ ){ + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + astGrfAttrs( this, gelid, 1, GRF__TEXT, method, class ); + +/* Plot them. */ + info = grid[ axis ]; + PlotLabels( this, esc, frame, axis, llist[ axis ], info->fmt, + nedge[ axis ], &box, method, class, status ); + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, gelid, 0, GRF__TEXT, method, class ); + +/* Set up the id for the next graphical element to be drawn. */ + gelid = AST__NUMLAB2_ID; + + } + +/* Free the memory used to hold the bounding boxes. */ + box = (float *) astFree( (void *) box ); + +/* Annul the pointer to the Frame. */ + frame = astAnnul( frame ); + } + +/* Free the memory used to store the label information. */ + for( axis = 0; axis < 2; axis++ ){ + ll = llist[ axis ]; + if( ll ) { + for( tick = 0; tick < nedge[ axis ]; tick ++ ) { + ll->text = (char *) astFree( (void *) ll->text ); + ll->just = (char *) astFree( (void *) ll->just ); + ll++; + } + llist[ axis ] = (LabelList *) astFree( (void *) llist[ axis ] ); + } + } + +/* Return the flag indicating if edge labels were produced. */ + return edgelabs; + +} + +static int EdgeCrossings( AstPlot *this, int edge, int axis, double axval, + double *gap, double **cross, + EdgeCrossingsStatics **pstatics, const char *method, + const char *class, int *status ){ +/* +* +* Name: +* EdgeCrossings + +* Purpose: +* Find all occurrences of a given physical axis value on an edge of the +* plotting area. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int EdgeCrossings( AstPlot *this, int edge, int axis, double axval, +* double *gap, double **cross, +* EdgeCrossingsStatics **pstatics, +* const char *method, const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function finds all occurences of a given physical axis value +* along a specified edge of the plotting area. Firstly, a set of evenly +* spaced points ("edge samples") are placed along the edge and the +* corresponding physical coordinates are found. These physical coordinates +* are then offset slightly from their original positions in the direction +* of the "other" axis (i.e. index [ 1 - axis ] ), and transformed back +* into graphics coordinates. These coordinates give the tangent vector +* at each of the edge samples. +* +* To find the crossings, the supplied axis value is compared with the axis +* value at each sample in turn, starting from one end of the edge and +* working through to the other end. When a crossing is found, linear +* interpolation is used between the two adjacent edge samples to find a +* more accurate estimate of the crossing. The vector at the crossing +* is also estimated by linear interpolation between the vectors at the two +* adjacent samples. +* +* This basic algorithm fails if there is a discontinuity in the axis +* values along the edge. For instance, if the edge covers a range of +* Right Ascension from 23h to 1h, there will be a discontinuity at 0h +* at which the RA values suddenly jump from 2*PI to zero. This jump +* encompasses all normalised RA values and so every axis value would be +* given a crossing at this point. To avoid this, a bad sample is +* interposed between the two samples on either side of the +* discontinuity. This prevents any crossings from being placed at the +* discontinuity. +* +* There is a second problem related to discontinuities. If the supplied +* axis value is zero (using the above RA example again), then no +* crossings will be found, not only because of the extra bad sample, +* but also because the samples will not quite cover the range of axis +* values covered by the discontinuity because of the discrete nature +* of the samples). To get round this, the sections on either side +* of the discontinity are extended by a single sample. These extra +* samples are assumed to be conincident with the neighbouring sample, +* except that the value for the searched axis is modified to be a +* linear extension from the neighbouring samples. + + +* Parameters: +* this +* A pointer to the Plot. Supply a NULL pointer to release resources. +* edge +* The edge of the plotting area to be used. Edge 0 is the left hand +* edge. Edge 1 is the top edge. Edge 2 is the right-hand edge. Edge 3 +* is the bottom edge. +* axis +* The index of the axis to which "axval" refers. +* axval +* The physical axis value to be searched for. +* gap +* Pointer to array of two values holding the gap between major +* tick marks on the two axes. +* cross +* A pointer to the location at which to return a pointer to an +* array of doubles holding the crossing information. Each crossing +* is described by 4 doubles. The first pair are the graphiucs (x,y) +* coordinates of the point on the edge at which the crossing occurs. +* The second pair represents a unit vector in graphics coordinates +* which is tangential to the curve of constant axis value at the +* crossing. The memory allocated within this function to hold this +* data should be freed using astFree when no longer needed. If no +* crossings are found a NULL pointer is returned. +* pstatics +* Address of a pointer to a structure holding values for variables +* which were statically defined within this function prior to the +* thread-safe version of AST. If the pointer is supplied as NULL, +* then a new structure is allocated and initialised. Any supplied +* structure is freed if a NULL pointer is supplied for "this". +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Return Value: +* The number of crossings found. + +* Notes: +* - This function allocates static resource on the first invocation +* which should be freed when no more calls are to be made, by making a +* final call with a NULL pointer supplied for "this". All other parameters +* are then ignored. +* - The static resources are re-initialised each time "edge" or +* "axis" changes, and so the calling function should be structure in +* order to minimise the number of times these parameter values change. +* - If an error has already occurred, or if this function should +* fail for any reason, zero is returned, and a NULL pointer is stored at +* "cross". + +*/ + +/* Local Variables: */ + EdgeCrossingsStatics *statics; /* Structure holding static data */ + AstMapping *mapping; /* Pointer to graphics->physical mapping */ + AstPointSet *pset1a; /* Physical cooords at offset edge samples */ + AstPointSet *pset2a; /* Physical cooords at offset edge samples */ + AstPointSet *pset3; /* Physical cooords at offset edge samples */ + AstPointSet *pset4a; /* Physical cooords at offset edge samples */ + double **ptr1a; /* Pointer to physical coord. data */ + double **ptr2a; /* Pointer to physical coord. data */ + double **ptr3; /* Pointer to physical coord. data */ + double **ptr4a; /* Pointer to physical coord. data */ + double *data; /* Pointer to next item of crossing information */ + double *p1; /* Pointer to graphics axis with constant value */ + double *p1a; /* Pointer to graphics axis with constant value */ + double *p2; /* Pointer to graphics axis with varying value */ + double *p2a; /* Pointer to graphics axis with varying value */ + double *q1; /* Pointer to physical axis being searched */ + double *q1a; /* Pointer to physical axis being searched */ + double *q2; /* Pointer to other physical axis */ + double *q2a; /* Pointer to other physical axis */ + double *v1; /* Pointer to vector component on axis 0 */ + double *v2; /* Pointer to vector component on axis 1 */ + double *v1a; /* Pointer to vector component on axis 0 */ + double *v2a; /* Pointer to vector component on axis 1 */ + double dd; /* The gap between edge samples */ + double diff; /* Squared differences between adjacent edge samples */ + double dl2; /* Squared vector length */ + double dl; /* Vector length */ + double dx; /* Vector X component */ + double dy; /* Vector Y component */ + double f; /* Weight for the current edge sample */ + double offset; /* Physical offset */ + double pp2; /* Varying graphics axis value at previous sample */ + double pq1; /* Required physical axis value at previous sample */ + double pv1; /* Previous vector component on axis 0 */ + double pv2; /* Previous vector component on axis 1 */ + double sum; /* Sum of squared differences between adjacent edge samples */ + double value; /* The current graphics axis value */ + double vx; /* Vector component on axis 0 at crossing */ + double vy; /* Vector component on axis 1 at crossing */ + double z; /* Varying graphics axis value at crossing */ + int i; /* Edge sample index */ + int iter; /* Iteration index */ + int larger; /* Is current axis value larger than target? */ + int logticks; /* Are major ticks logarithmically spaced? */ + int ncross; /* No. of crossings */ + int ndisc; /* No. of discontinuities along the edge */ + int nsum; /* Number of values summed in "sum" */ + int plarger; /* Was previous axis value larger than target? */ + +/* Get a pointer to the supplied statics object. */ + statics = *pstatics; + +/* If a NULL Plot pointer has been supplied, release the static + resources, and return. */ + if( !this ){ + if( statics ){ + if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); + if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); + if( statics->pset4 ) statics->pset4 = astAnnul( statics->pset4 ); + if( statics->frame ) statics->frame = astAnnul( statics->frame ); + *pstatics = astFree( statics ); + } + return 0; + } + +/* Initialise the number of crossings found, and the pointer to the place + to store them. */ + ncross = 0; + *cross = NULL; + +/* Check the global status. */ + if( !astOK ) return 0; + +/* If no statics structure was supplied, create one now and initialise it. */ + if( !statics ) { + statics = astMalloc( sizeof( EdgeCrossingsStatics ) ); + if( statics ) { + statics->frame = NULL; + statics->pset1 = NULL; + statics->pset2 = NULL; + statics->pset4 = NULL; + statics->ptr1 = NULL; + statics->ptr2 = NULL; + statics->ptr4 = NULL; + statics->paxis = -1; + statics->pedge = -1; + *pstatics = statics; + } + } + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + pp2 = 0.0; + pv1 = 0.0; + pv2 = 0.0; + plarger = 0; + +/* See if the major ticks on the other axis are logarithmically or + linearly spaced. */ + logticks = astGetLogTicks( this, 1 - axis ); + +/* Ensure that "edge" is in the range 0 - 3. */ + edge = edge % 4; + if( edge < 0 ) edge = -edge; + +/* If the edge or axis has changed since the last invocation, or if this is + the first invocation, initialise some static data. */ +/* ======================================================================*/ + if( statics->pedge == -1 || statics->pedge != edge || statics->paxis != axis ){ + +/* Save the edge and axis. */ + statics->pedge = edge; + statics->paxis = axis; + +/* Annull any previous static data objects */ + if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); + if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); + if( statics->pset4 ) statics->pset4 = astAnnul( statics->pset4 ); + if( statics->frame ) statics->frame = astAnnul( statics->frame ); + +/* Store some values so that the code does not need to consider each edge + separately. First deal with the left hand edge. */ + if( edge == 0 ){ + statics->edgeax = 0; + if( this->xrev ){ + statics->edgeval = this->xhi; + } else { + statics->edgeval = this->xlo; + } + statics->edgehi = this->yhi; + statics->edgelo = this->ylo; + +/* Now deal with the right hand edge. */ + } else if( edge == 2 ){ + statics->edgeax = 0; + if( this->xrev ){ + statics->edgeval = this->xlo; + } else { + statics->edgeval = this->xhi; + } + statics->edgehi = this->yhi; + statics->edgelo = this->ylo; + +/* Now deal with the bottom edge. */ + } else if( edge == 3 ){ + statics->edgeax = 1; + if( this->yrev ){ + statics->edgeval = this->yhi; + } else { + statics->edgeval = this->ylo; + } + statics->edgehi = this->xhi; + statics->edgelo = this->xlo; + + +/* Finally deal with the top edge. */ + } else { + statics->edgeax = 1; + if( this->yrev ){ + statics->edgeval = this->ylo; + } else { + statics->edgeval = this->yhi; + } + statics->edgehi = this->xhi; + statics->edgelo = this->xlo; + + } + +/* Get a pointer to the current Frame in the supplied Plot. */ + statics->frame = astGetFrame( this, AST__CURRENT ); + +/* Get a pointer to the mapping from base to current Frame in the supplied + Plot. */ + mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); + +/* Create a PointSet to hold the graphics coordinates at a set of + regularly spaced points along the specified edge of the plotting area. */ + pset1a = astPointSet( EDGETICKS_DIM, 2, "", status ); + ptr1a = astGetPoints( pset1a ); + +/* Create a PointSet to hold the corresponding physical coordinates. */ + pset2a = astPointSet( EDGETICKS_DIM, 2, "", status ); + ptr2a = astGetPoints( pset2a ); + +/* Check they can be used. */ + if( astOK ){ + +/* Set up the graphics coordinates. */ + dd = ( statics->edgehi - statics->edgelo )/(double)( EDGETICKS_DIM - 1 ); + value = statics->edgelo; + + p1 = ptr1a[ statics->edgeax ]; + p2 = ptr1a[ 1 - statics->edgeax ]; + + for( i = 0; i < EDGETICKS_DIM; i++ ){ + *(p1++) = statics->edgeval; + *(p2++) = value; + value += dd; + } + } + +/* Transform the graphics coordinates to physical coordinates, + *without* normalising them into their normal ranges. */ + (void) Trans( this, statics->frame, mapping, pset1a, 1, pset2a, 0, method, class, status ); + +/* Find the RMS step size along the axis. This is used to locate + discontinuities along the edge. Do three rejection iterations. */ + statics->limit = DBL_MAX; + for( iter = 0; iter < 3; iter ++ ){ + q1 = ptr2a[ axis ]; + pq1 = AST__BAD; + sum = 0.0; + nsum = 0; + + for( i = 0; i < EDGETICKS_DIM; i++ ){ + if( *q1 != AST__BAD && pq1 != AST__BAD ){ + diff = *q1 - pq1; + if( fabs( diff ) < statics->limit ){ + sum += diff*diff; + nsum++; + } + } + pq1 = *(q1++); + } + + if( nsum == 0 ) break; + statics->limit = 3.0*sqrt( sum/(double)nsum ); + } + +/* Now create another PointSet holding positions slightly offset from the + physical coordinates at the edge samples. The offset is in the direction + of the other physical axis. These positions are used to determine the + vector at the crossings. */ + if( nsum > 0 ){ + pset3 = astPointSet( EDGETICKS_DIM, 2, "", status ); + ptr3 = astGetPoints( pset3 ); + +/* Create a PointSet to hold the corresponding graphics coordinates. */ + pset4a = astPointSet( EDGETICKS_DIM, 2, "", status ); + ptr4a = astGetPoints( pset4a ); + +/* Check they can be used. */ + if( astOK ){ + +/* Copy the physical coordinates from PointSet 2 to PointSet 3, offseting + them slightly along the other axis. */ + p1 = ptr2a[ axis ]; + p2 = ptr2a[ 1 - axis ]; + + q1 = ptr3[ axis ]; + q2 = ptr3[ 1 - axis ]; + + offset = 0.2*gap[ 1 - axis ]; + + pq1 = AST__BAD; + + for( i = 0; i < EDGETICKS_DIM; i++ ){ + if( *p1 != AST__BAD && *p2 != AST__BAD ){ + if( logticks ) offset = 0.2*(*p2)*( gap[ 1 -axis ] - 1.0 ); + *(q2++) = *p2 + offset; + } else { + *(q2++) = AST__BAD; + } + pq1 = *(p1++); + *(q1++) = pq1; + p2++; + } + + } + +/* Transform the physical coordinates to graphics coordinates. */ + (void) Trans( this, NULL, mapping, pset3, 0, pset4a, 0, method, class, status ); + +/* Check they can be used. */ + if( astOK ){ + +/* Modify the contents of PointSet 4 to represent the unit vector in + graphics coordinates at each edge sample. */ + p1 = ptr1a[ 0 ]; + p2 = ptr1a[ 1 ]; + q1 = ptr4a[ 0 ]; + q2 = ptr4a[ 1 ]; + + for( i = 0; i < EDGETICKS_DIM; i++ ){ + if( *p1 != AST__BAD && *p2 != AST__BAD && + *q1 != AST__BAD && *q2 != AST__BAD ){ + + dx = *q1 - *p1; + dy = *q2 - *p2; + dl2 = dx*dx + dy*dy; + + if( dl2 > 0.0 ){ + dl = sqrt( dl2 ); + *q1 = dx/dl; + *q2 = dy/dl; + } else { + *q1 = AST__BAD; + *q2 = AST__BAD; + } + + } else { + *q1 = AST__BAD; + *q2 = AST__BAD; + } + + p1++; + p2++; + q1++; + q2++; + + } + + } + +/* Annul the PointSet holding offset physical cooridnates. */ + pset3 = astAnnul( pset3 ); + +/* Discontinuities in the axis values can cause problems. For instance, + using the above PointSets, no tick mark could be put at 0 hours RA + because of the discontinuity there. To get round this, 3 extra samples + are added at each discontinuity, the first extends the continuous section + which ends at the discontinuity, and the third extends the secion which + starts at the discontinuity. This results in the two sections overlapping + by one sample. The second is placed between these two and has a bad + axis value. It prevents crossings from being found in between the values + at the ends of the two sections. + + First count the number of discontinuities in the axis values. + Discontinuites are defined as steps of more than 9 times the RMS step + size. */ + q1 = ptr2a[ axis ]; + pq1 = AST__BAD; + statics->limit *= 3.0; + ndisc = 0; + + for( i = 0; i < EDGETICKS_DIM; i++ ){ + if( *q1 != AST__BAD && pq1 != AST__BAD ){ + if( fabs( *q1 - pq1 ) > statics->limit ) ndisc++; + } + pq1 = *(q1++); + } + +/* Store the size of the new PointSets holding the extra samples. */ + statics->dim = EDGETICKS_DIM + 3*ndisc; + +/* If there are no discontinuities, just clone the existing PointSets. */ + if( !ndisc ){ + statics->pset1 = astClone( pset1a ); + statics->pset2 = astClone( pset2a ); + statics->pset4 = astClone( pset4a ); + statics->ptr1 = astGetPoints( statics->pset1 ); + statics->ptr2 = astGetPoints( statics->pset2 ); + statics->ptr4 = astGetPoints( statics->pset4 ); + +/* Otherwise, create new PointSets. */ + } else { + statics->pset1 = astPointSet( statics->dim, 2, "", status ); + statics->ptr1 = astGetPoints( statics->pset1 ); + statics->pset2 = astPointSet( statics->dim, 2, "", status ); + statics->ptr2 = astGetPoints( statics->pset2 ); + statics->pset4 = astPointSet( statics->dim, 2, "", status ); + statics->ptr4 = astGetPoints( statics->pset4 ); + +/* Set up pointers used to walk through the arrays in the original + PointSets and the new PointSets. */ + p1 = statics->ptr1[ 0 ]; + p2 = statics->ptr1[ 1 ]; + q1 = statics->ptr2[ axis ]; + q2 = statics->ptr2[ 1 - axis ]; + v1 = statics->ptr4[ 0 ]; + v2 = statics->ptr4[ 1 ]; + + p1a = ptr1a[ 0 ]; + p2a = ptr1a[ 1 ]; + q1a = ptr2a[ axis ]; + q2a = ptr2a[ 1 - axis ]; + v1a = ptr4a[ 0 ]; + v2a = ptr4a[ 1 ]; + +/* Initialise the axis value at the previous sample. */ + pq1 = AST__BAD; + +/* Check all samples in the original PointSets. */ + for( i = 0; i < EDGETICKS_DIM; i++ ){ + +/* If this is the first point after a discontinuity... */ + if( *q1a != AST__BAD && pq1 != AST__BAD ){ + if( fabs( *q1a - pq1 ) > statics->limit ) { + +/* Insert an extra sample with the coordinates of the previous sample, + but with an axis value which is linearly extrapolated from the previous + samples. */ + *(p1++) = p1a[ 0 ]; + *(p2++) = p2a[ 0 ]; + *(v1++) = v1a[ -1 ]; + *(v2++) = v2a[ -1 ]; + *(q2++) = q2a[ -1 ]; + if( i > 1 && q1a[ -2 ] != AST__BAD ){ + *(q1++) = 2.0*pq1 - q1a[ -2 ]; + } else { + *(q1++) = pq1; + } + +/* Insert an extra sample with bad coordinates. */ + *(p1++) = AST__BAD; + *(p2++) = AST__BAD; + *(v1++) = AST__BAD; + *(v2++) = AST__BAD; + *(q2++) = AST__BAD; + *(q1++) = AST__BAD; + +/* Insert an extra sample with the cooridnates of the current sample, + but with an axis value which is linearly extrapolated from the + subsequent samples. */ + *(p1++) = p1a[ -1 ]; + *(p2++) = p2a[ -1 ]; + *(v1++) = *v1a; + *(v2++) = *v2a; + *(q2++) = *q2a; + if( i < EDGETICKS_DIM - 1 && q1a[ 1 ] != AST__BAD ){ + *(q1++) = 2.0*(*q1a) - q1a[ 1 ]; + } else { + *(q1++) = pq1; + } + + } + + } + +/* Save the current axis value. */ + pq1 = *q1a; + +/* Copy the current input values to the new PointSets, and move on the next + point in the original PointSets. */ + *(p1++) = *(p1a++); + *(p2++) = *(p2a++); + *(q1++) = *(q1a++); + *(q2++) = *(q2a++); + *(v1++) = *(v1a++); + *(v2++) = *(v2a++); + + } + + } + +/* Anull the original PointSets. */ + pset4a = astAnnul( pset4a ); + +/* If all the physical coordinates are bad, indicate this by setting the + limiting step size bad. */ + } else { + statics->limit = AST__BAD; + } + +/* Anull the original PointSets. */ + pset1a = astAnnul( pset1a ); + pset2a = astAnnul( pset2a ); + +/* Annul the pointer to the mapping from base to current Frame. */ + mapping = astAnnul( mapping ); + + } + +/* ======================================================================*/ +/* The initialisation has now been done. Check the physical coordinate data + can be used. */ + if( astOK && statics->limit != AST__BAD ){ + +/* Store pointers to the graphics and physical coordinates at the first + edge sample. */ + p1 = statics->ptr1[ statics->edgeax ]; /* Graphics axis with constant value */ + p2 = statics->ptr1[ 1 - statics->edgeax ]; /* Graphics axis with varying value */ + q1 = statics->ptr2[ axis ]; /* Physical axis values to be searched */ + q2 = statics->ptr2[ 1 - axis ]; /* The other physical axis */ + +/* Store pointers to the components of the unit vector at the first + edge sample. */ + v1 = statics->ptr4[ 0 ]; + v2 = statics->ptr4[ 1 ]; + +/* Inidicate that there is currently no "previous sample". */ + pq1 = AST__BAD; + +/* Check each point in turn... */ + for( i = 0; i < statics->dim; i++ ){ + +/* Skip this point if the physical coordinates are undefined. */ + if( *q1 != AST__BAD && *q2 != AST__BAD ){ + +/* Get a flag indicating if the required axis value has been exceeded at + the current edge sample. */ + larger = ( *q1 > axval ); + +/* If the state of this flag has changed since the previous edge sample, + and if we know where the previous sample was, we have found a + crossing. */ + if( pq1 != AST__BAD && larger != plarger ){ + +/* Find the distance from the previous physical axis value to the required + axis value, as a fraction of the distance from the previous axis value + to the current axis value. Since the flag has changed, we know that the + q1 value at this edge sample and the previous one must be different, so + we know that the denominator is not zero. */ + f = ( axval - pq1 )/( *q1 - pq1 ); + +/* Use linear interpolation to estimate the graphics axis value at the + crossing. */ + if( f != -1.0 ){ + z = pp2 + f*( *p2 - pp2 ); + +/* Use linear interpolation to estimate the two components of the unit + vector at the crossing. */ + if( *v1 != AST__BAD && pv1 != AST__BAD && + *v2 != AST__BAD && pv2 != AST__BAD ){ + vx = pv1 + f*( *v1 - pv1 ); + vy = pv2 + f*( *v2 - pv2 ); + +/* Normalise the vector. */ + dl2 = vx*vx + vy*vy; + if( dl2 > 0.0 ){ + dl = sqrt( dl2 ); + vx /= dl; + vy /= dl; + } else { + vx = AST__BAD; + vy = AST__BAD; + } + + } else { + vx = AST__BAD; + vy = AST__BAD; + } + +/* Grow the returned array to hold another crossing. */ + ncross++; + *cross = (double *) astGrow( (void *) *cross, ncross, + 4*sizeof( double ) ); + +/* If succesful, store the crossing. */ + if( astOK ) { + + data = *cross + 4*( ncross - 1 ); + if( statics->edgeax ){ + *(data++) = z; + *(data++) = statics->edgeval; + } else { + *(data++) = statics->edgeval; + *(data++) = z; + } + *(data++) = vx; + *(data++) = vy; + + } + + } + + } + +/* Save the flag for use on the next pass through this loop. */ + plarger = larger; + + } + +/* Save the varying graphics axis value and the required physical axis + value at the current edge sample (also save the vector). */ + pp2 = *p2; + pq1 = *q1; + pv1 = *v1; + pv2 = *v2; + +/* Point to the next edge sample. */ + p1++; + p2++; + q1++; + q2++; + v1++; + v2++; + + } + + } + +/* If an error has occurred, free the array holding the crossings, and + indicate that there are zero corssing. */ + if( !astOK ) { + *cross = (double *) astFree( (void *) *cross ); + ncross = 0; + } + +/* Return the answer. */ + return ncross; + +} + +int astFindEscape_( const char *text, int *type, int *value, int *nc, int *status ){ +/* +*+ +* Name: +* astFindEscape + +* Purpose: +* Check if a string starts with a graphics escape sequence. + +* Type: +* Protected function. + +* Synopsis: +* #include "plot.h" +* int astFindEscape( const char *text, int *type, int *value, int *nc ) + +* Description: +* This function returns a flag indiciating if the first character in +* the supplied string is the start of a graphics escape sequence. If +* so, the type and associated value (if any) of the escape sequence +* are returned in "type" and "value", and the number of characters +* occupied by the escape sequence is returned in "nc". If the +* supplied text string does not begin with an escape sequence, the +* number of characters before the first escape sequence is returned in +* "nc" (the length of the string is returned in "nc" if the string +* contains no escape sequences). +* +* This function can be used by grf modules which wish to implement +* interpretation of escape sequences internally, rather than allowing the +* Plot class to do the interpretation. + +* Parameters: +* text +* Pointer to the string to be checked. +* type +* Pointer to a location at which to return the type of escape +* sequence. Each type is identified by a symbolic constant defined +* in grf.h. The returned value is undefined if the supplied text +* does not begin with an escape sequence. +* value +* Pointer to a lcation at which to return the integer value +* associated with the escape sequence. All usable values will be +* positive. Zero is returned if the escape sequence has no associated +* integer. A value of -1 indicates that the attribute identified by +* "type" should be reset to its "normal" value (as established using +* the astGAttr function, etc). The returned value is undefined if the +* supplied text does not begin with an escape sequence. +* nc +* Pointer to a location at which to return the number of +* characters read by this call. If the text starts with an escape +* sequence, the returned value will be the number of characters in +* the escape sequence. Otherwise, the returned value will be the +* number of characters prior to the first escape sequence, or the +* length of the supplied text if no escape sequence is found. + +* Returned Value: +* A non-zero value is returned if the supplied text starts with a +* graphics escape sequence, and zero is returned otherwise. + +* Escape Sequences: +* Escape sequences are introduced into the text string by a percent +* "%" character. The following escape sequences are currently recognised +* ("..." represents a string of one or more decimal digits): +* +* %% - Print a literal "%" character. +* +* %^...+ - Draw subsequent characters as super-scripts. The digits +* "..." give the distance from the base-line of "normal" +* text to the base-line of the super-script text, scaled +* so that a value of "100" corresponds to the height of +* "normal" text. +* %^+ - Draw subsequent characters with the normal base-line. +* +* %v...+ - Draw subsequent characters as sub-scripts. The digits +* "..." give the distance from the base-line of "normal" +* text to the base-line of the sub-script text, scaled +* so that a value of "100" corresponds to the height of +* "normal" text. +* +* %v+ - Draw subsequent characters with the normal base-line +* (equivalent to %^+). +* +* %>...+ - Leave a gap before drawing subsequent characters. +* The digits "..." give the size of the gap, scaled +* so that a value of "100" corresponds to the height of +* "normal" text. +* +* %<...+ - Move backwards before drawing subsequent characters. +* The digits "..." give the size of the movement, scaled +* so that a value of "100" corresponds to the height of +* "normal" text. +* +* %s...+ - Change the Size attribute for subsequent characters. The +* digits "..." give the new Size as a fraction of the +* "normal" Size, scaled so that a value of "100" corresponds +* to 1.0; +* +* %s+ - Reset the Size attribute to its "normal" value. +* +* %w...+ - Change the Width attribute for subsequent characters. The +* digits "..." give the new width as a fraction of the +* "normal" Width, scaled so that a value of "100" corresponds +* to 1.0; +* +* %w+ - Reset the Size attribute to its "normal" value. +* +* %f...+ - Change the Font attribute for subsequent characters. The +* digits "..." give the new Font value. +* +* %f+ - Reset the Font attribute to its "normal" value. +* +* %c...+ - Change the Colour attribute for subsequent characters. The +* digits "..." give the new Colour value. +* +* %c+ - Reset the Colour attribute to its "normal" value. +* +* %t...+ - Change the Style attribute for subsequent characters. The +* digits "..." give the new Style value. +* +* %t+ - Reset the Style attribute to its "normal" value. +* +* %h+ - Remember the current horizontal position (see "%g+") +* +* %g+ - Go to the horizontal position of the previous "%h+" (if any). +* +* %- - Push the current graphics attribute values onto the top of +* the stack (see "%+"). +* +* %+ - Pop attributes values of the top the stack (see "%-"). If +* the stack is empty, "normal" attribute values are restored. + +* Notes: +* - Zero is returned if an error has already occurred. +*- +*/ + +/* Local Variables: */ + int result; + const char *a; + const char *b; + int nd; + const char *perc; + +/* Initialise */ + result = 0; + *type = GRF__ESPER; + *value = 0; + *nc = 0; + perc = NULL; + +/* Check inherited status and supplied pointer. */ + if( !astOK || !text ) return result; + +/* Loop round, looking for percent signs. Break out of the loop when a + complete escape sequence has been found and read, leaving the "b" pointer + pointing to the first character following the escape sequence. */ + b = NULL; + a = text; + while( ( a = strchr( a, '%' ) ) ) { + perc = a; + +/* Compare the following character to each known escape sequence type. */ + a++; + if( *a == '%') { + *type = GRF__ESPER; + b = a + 1; + break; + + } else if( *a == '^') { + *type = GRF__ESSUP; + + } else if( *a == 'v') { + *type = GRF__ESSUB; + + } else if( *a == '>') { + *type = GRF__ESGAP; + + } else if( *a == '<') { + *type = GRF__ESBAC; + + } else if( *a == 's') { + *type = GRF__ESSIZ; + + } else if( *a == 'w') { + *type = GRF__ESWID; + + } else if( *a == 'f') { + *type = GRF__ESFON; + + } else if( *a == 'c') { + *type = GRF__ESCOL; + + } else if( *a == 'g') { + *type = GRF__ESG; + + } else if( *a == 'h') { + *type = GRF__ESH; + + } else if( *a == 't') { + *type = GRF__ESSTY; + + } else if( *a == '-') { + *type = GRF__ESPSH; + b = a + 1; + break; + + } else if( *a == '+') { + *type = GRF__ESPOP; + b = a + 1; + break; + +/* If the next character is illegal, skip to the next percent sign. */ + } else { + continue; + } + +/* The escape sequence looks legal so far, so move on to the next + character (if any). */ + if( *(++a) ){ + +/* If the next character is a "+" sign, the attribute needs to be reset + to its "normal" value. Indicate this by returning a value of "-1" (all + usable values will be positive). */ + if( *a == '+' ) { + *value = -1; + b = a + 1; + break; + +/* Otherwise, to be a legal escape sequence, this character must be the + first in a sequence of digits, terminated by a "+" sign.*/ + } else if( (nd = 0, astSscanf( a, "%d%n+", value, &nd ))) { + b = a + nd + 1; + break; + } + } + } + +/* Was a usable escape sequence found at the start of the supplied text? + If so, return a function value of 1 and store the number of characters in + the escape sequence. */ + if( b && perc == text ) { + result = 1; + *nc = b - perc; + +/* Otherwise, return the preset function value of zero. If an escape + sequence was found later in the text, return the number of characters + prior to the escape sequence. */ + } else if( b ) { + *nc = perc - text; + +/* Otherwise, if no escape sequence was found, return the length of the + supplied text. */ + } else { + *nc = strlen( text ); + } + +/* Return the result. */ + return result; +} + +static int FindMajTicks( AstMapping *map, AstFrame *frame, int axis, + double refval, double width, double gap, double *cen, int ngood, + double *data, double **tick_data, int *status ){ +/* +* Name: +* FindMajTicks + +* Purpose: +* Place the major tick marks for a physical coordinate axis. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int FindMajTicks( AstMapping *map, AstFrame *frame, int axis, +* double refval, double width, double gap, double *cen, int ngood, +* double *data, double **tick_data ) + +* Class Membership: +* Plot member function. + +* Description: +* The caller supplies an array of axis values (non-normalized), sorted +* into ascending order (with any bad values at the end), together with +* the gap size for the axis. The array of axis values is assumed to cover +* the entire range which the axis can take within the plotting zone. The +* first tick mark is placed just below the smallest axis value, at a +* position which is an integral number of gaps away from the value +* supplied in "cen" (if a value of AST__BAD is supplied for "cen" then +* "cen = 0.0" is assumed). Notionally, tick marks are then placed at +* intervals given by "gap" all the way upto, and just beyond, the +* largest axis value. However, it could be that large sections of the +* axis are not actually present within the plotting zone. For instance, +* an RA axis covering the two hour range from 23h to 1h (centred on +* 0h), will have some values at zero and some at 23.999.., but there +* will be a large range inbetween these limits which is not represented +* in the plotting area (i.e. the 22h range from 1h to 23h centred on +* 12h). For this reason, tick marks are removed if there are no axis +* values inbetween the tick mark and either of its neighbours. However, +* small "holes" in the axis coverage are allowed, and ticks marks are +* returned covering such small holes. Extra tick marks are also placed +* at each end of the range to guard against the supplied array of axis +* values not entirely covering the range of axis values in the plotting +* area. +* +* For SkyFrames, positions which have latitude values outside the +* normal ranges are ignored. Longitude ranges are not checked to +* avoid problems with CAR projections. +* +* The returned tick mark values are placed into their primary domain +* using the Norm1 method, but are NOT normalised using the astNorm +* method for the supplied Frame. Duplicate tick marks values are +* removed from the returned list. + +* Parameters: +* map +* Mapping from the Plot Base Frame to Plot Current Frame. +* frame +* Pointer to the Frame. +* axis +* Zero-based index of the axis being used. +* refval +* Value to use for the other axis (index [1-axis]) when placing +* the tick mark values into their primary domain. +* width +* Range of used values on the other axis (index [1-axis]). +* gap +* The supplied value for the gaps between ticks on the axis. +* cen +* Pointer to the supplied axis value at which to put a central tick. +* Other ticks will be placed evenly on either side of this tick. If +* AST__BAD is provided, a value will be used which would put a tick +* at an axis value of zero. The used value is returned. +* ngood +* The number of good values in the array pointer to by "data" (i.e. +* values not equal to AST__BAD). +* data +* A pointer to an array holding sorted axis values (non-normalized) +* covering the entire plotting area. +* tick_data +* A pointer to a place at which to store a pointer to an array +* holding the returned tick mark values for the axis. + +* Returned Value: +* The number of major tick mark values stored in the array pointer to +* by "*tick_data". + +* Notes: +* - If an error has already occurred, or if this function should fail +* for any reason, then a NULL pointer is returned in "tick_data", and zero +* is returned for the function value. +*/ + +/* Local Variables: */ + double *r; /* Pointer to next tick value to be read */ + double *ticks; /* Pointer to the axis values at the major tick marks */ + double *w; /* Pointer to last tick value to be written */ + double bot; /* Lowest axis value to be displayed */ + double centre; /* The axis value at the first tick mark */ + double delta; /* A safe distance from an axis limit */ + double f; /* The nearest acceptable tick mark index */ + double tmp; /* Temporary storage */ + double top; /* Highest axis value to be displayed */ + int inc; /* This times increase in nticks */ + int k; /* Tick mark index */ + int linc; /* Last times increase in nticks */ + int lnfill; /* Last used value for nfill */ + int nfill; /* No of tick marks to extend by at edges of coverage */ + int nsame; /* Number of equal inc values there have been */ + int nticks; /* Number of major tick marks used */ + int ntnew; /* This times new value of nticks */ + int use_nfill; /* nfill value which started this run of equal inc values */ + +/* Initialise the returned pointer. */ + *tick_data = NULL; + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + nsame = 0; + use_nfill = 0; + +/* Decide where to put the first major tick. Use any value supplied by + the caller. Otherwise put it an integral number of gaps away from the + origin. This would result in the origin being at a major tick mark. */ + if( cen && *cen != AST__BAD ) { + centre = *cen; + } else { + centre = astCentre( frame, axis, data[ 0 ], gap ); + if( cen ) *cen = centre; + } + +/* Find the number of candidate tick marks assuming an nfill value of 0. */ + nfill = 0; + nticks = FindMajTicks2( nfill, gap, centre, ngood, data, &ticks, status ); + +/* Loop round increasing the nfill value until an unreasonably large value + of nfill is reached. The loop will exit early via a break statement when + all small holes in the axis coverage are filled in. */ + lnfill = nfill; + linc = -100000; + while( nfill < 100 && astOK ){ + +/* Increment the number of ticks added as "padding" at the edges of any + gaps in the coverage of axis values. */ + nfill++; + +/* Form a new set of tick mark values using this new nfill value */ + ticks = (double *) astFree( (void *) ticks ); + ntnew = FindMajTicks2( nfill, gap, centre, ngood, data, &ticks, status ); + +/* We need to know if the rate of increase of nticks has settled down to + a constant value. Inititially increasing nfill will cause the total + number of ticks (nticks) to increase rapidly. But this rate of + increase will get less as any small gaps in axis coverage are filled in. + We break out of the while loop when the rate of increase has settled + down to a constant value (indicating that only very large holes are left + in the axis coverage). Find the increase in the number of ticks caused by + the increase in the nfill value made in this loop. If this increase is the + same as the increase caused by the previous loop, increment the number of + equal increases there have been. If the increase is different to last time, + reset the number of equal increases to zero. */ + inc = ntnew - nticks; + if( inc == linc ) { + nsame++; + } else { + nsame = 0; + use_nfill = nfill; + } + +/* If the past 3 increases in nfill has not caused any change in the rate + of increase of nticks, then re-create the ticks for the value of nfill + which started the current run of equal increment values, and leave the + loop. */ + if( nsame == 3 ) { + ticks = (double *) astFree( (void *) ticks ); + nticks = FindMajTicks2( use_nfill, gap, centre, ngood, data, &ticks, status ); + break; + } + +/* Save this times values for use in the next loop. */ + linc = inc; + nticks = ntnew; + } + +/* Remove ticks which are not within the axis ranges to be displayed. + Ticks which are very close to the limit are moved to a safe (but + visually negligable) distance away from the limit). */ + bot = astGetBottom( frame, axis ); + top = astGetTop( frame, axis ); + if( bot > top ) { + tmp = top; + top = bot; + bot = tmp; + } + delta = 0.05*gap; + r = ticks; + for( k = 0; k < nticks; k++ ){ + if( *r != AST__BAD ) { + if( fabs( *r - bot ) < delta ) { + *r = bot + delta; + } else if( fabs( *r - top ) < delta ) { + *r = top - delta; + } else if( *r < bot || *r > top ) { + *r = AST__BAD; + } + } + r++; + } + +/* Use the Mapping to place each tick mark value in its primary domain. + This is a sort of normalization, similar but different to that performed + by the astNorm method. */ + Norm1( map, axis, nticks, ticks, refval, width, status ); + +/* Check for success. */ + if( astOK ){ + +/* Ensure that all ticks marks are offset from the "centre" value by an + integer multiple of the gap size. This is done by changing each tick + value to the closest acceptable value. Also ensure that values close to + zero (i.e. less than 1E-10 of the gap size) are set exactly to zero. */ + r = ticks; + for( k = 0; k < nticks; k++ ){ + if( *r != AST__BAD ) { + f = floor( 0.5 + ( *r - centre )/gap ); + *r = f*gap + centre; + if( fabs( *r ) < 1.0E-10*gap ) *r = 0.0; + r++; + } else { + r++; + } + } + +/* Sort the tick values into increasing order. */ + qsort( (void *) ticks, (size_t) nticks, sizeof(double), Compared ); + +/* Remove any duplicate or BAD tick values by shuffling the higher unique + values down to over-write them. We subtract the centre value of both + tick values before comparing them for equality in order to avoid + unnecessarily removing tick marks in high precsion data. */ + r = ticks + 1; + w = ticks; + for( k = 1; k < nticks && astOK; k++ ){ + if( *r != AST__BAD && !astEQUALS( *r-centre, *w-centre, 1.0E8 ) ){ + w++; + *w = *r; + } + r++; + } + +/* Modify the number of ticks to exclude the duplicate ones. */ + nticks = (int) ( w - ticks ) + 1; + + } + +/* If an error has occurred, free the memory holding the major tick mark + values, and indicate that zero tick marks have been found. */ + if( !astOK ){ + ticks = (double *) astFree( (void *) ticks ); + nticks = 0; + } + +/* Store the pointer to the major tick mark values. */ + *tick_data = ticks; + +/* Return the number of major ticks. */ + return nticks; + +} +static int FindMajTicks2( int nfill, double gap, double centre, int ngood, + double *data, double **tick_data, int *status ){ +/* +* Name: +* FindMajTicks2 + +* Purpose: +* Find candidate major tick marks for FindMajTicks. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int FindMajTicks2( int nfill, double gap, double centre, int ngood, +* double *data, double **tick_data, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* A service routine for function FindMajTicks. + +* Parameters: +* nfill +* Number of tick marks to extend by at edges of coverage +* gap +* The supplied value for the gaps between ticks on the axis. +* centre +* The supplied axis value at which to put a central tick. +* ngood +* The number of good values in the array pointer to by "data" (i.e. +* values not equal to AST__BAD). +* data +* A pointer to an array holding sorted axis values covering the +* entire plotting area. +* tick_data +* A pointer to a place at which to store a pointer to an array +* holding the returned tick mark values for the axis. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The number of major tick mark values stored in the array pointer to +* by "*tick_data". + +* Notes: +* - If an error has already occurred, or if this function should fail +* for any reason, then a NULL pointer is returned in "tick_data", and zero +* is returned for the function value. +*/ + +/* Local Variables: */ + double *ticks; /* Pointer to the axis values at the major tick marks */ + int i; /* Index of current axis value */ + int j; /* Index of filled in tick */ + int k; /* Tick mark index */ + int klast; /* Index of the previous tick mark */ + int nticks; /* Number of major tick marks used */ + +/* Initialise the returned pointer. */ + *tick_data = NULL; + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + nticks = 0; + +/* Reserve memory to hold a reasonable number of tick mark axis values. + This memory is later extended as necessary. */ + ticks = (double *) astMalloc( sizeof(double)*( 6*nfill + 14 ) ); + +/* Check that the pointer can be used. */ + if( astOK ){ + +/* Put the first tick marks just below the lowest axis value (in case + the grid did not sample the entire range of the axis). */ + k = floor( ( data[ 0 ] - centre )/gap ); + + for ( i = 0; i < nfill; i++ ){ + ticks[ i ] = gap*(double)( k - nfill + i ) + centre; + } + ticks[ nfill ] = gap*(double)( k ) + centre; + +/* Initialise the number of major tick marks found so far. */ + nticks = nfill + 1; + +/* Loop round each of the remaining good ordered axis values. */ + klast = k; + for( i = 1; i < ngood && astOK; i++ ) { + +/* Find the tick marks enclosing the axis value. The tick mark placed at + "centre" is called tick mark zero, and tick marks are indexed (positive + or negative) from an origin at "centre". Find the index of the more + negative of the two tick marks enclosing the axis value. */ + k = floor( ( data[ i ] - centre )/gap ); + +/* Ensure that the tick marks enclosing the current axis value are used. + Some extra tick marks are used at the start and end of any gaps in + the axis coverage. This is done to "fill in" small holes caused by the + grid of physical coordinate values not completely covering the + plotting area. Large holes, such as occur on an RA axis covering the 2 + hour range from 23 hours to 1 hour are left without any tick marks in + them (the "hole" in this case is the 22 hours range from 1 hour to 23 + hours). */ + for( j = 0; j < nfill + 1; j++ ){ + if( k - klast > nfill + 2 - j ) { + ticks = (double *) astGrow( ticks, nticks + 1, sizeof( double ) ); + if( astOK ) ticks[ nticks++ ] = + gap*(double)( klast + nfill + 1 - j ) + centre; + } + if( k - klast > nfill - j ) { + ticks = (double *) astGrow( ticks, nticks + 1, sizeof( double ) ); + if( astOK ) ticks[ nticks++ ] = + gap*(double)( k - nfill + j ) + centre; + } + } + +/* Save the index of the current tick mark. */ + klast = k; + + } + +/* Add extra tick marks beyond the end in case the grid did not sample + the entire range of the axis. */ + ticks = (double *) astGrow( ticks, nticks + nfill + 1, sizeof( double ) ); + for( i = 0; i < nfill && astOK; i++ ){ + ticks[ nticks++ ] = gap*(double)( klast + i + 1 ) + centre; + } + + } + +/* If an error has occurred, free the memory holding the major tick mark + values, and indicate that zero tick marks have been found. */ + if( !astOK ){ + ticks = (double *) astFree( (void *) ticks ); + nticks = 0; + } + +/* Store the pointer to the major tick mark values. */ + *tick_data = ticks; + +/* Return the number of major ticks. */ + return nticks; + +} + +static int FindDPTZ( AstFrame *fr, int axis, const char *fmt, + const char *text, int *ndp, int *ntz, int *status ) { +/* +* Name: +* FindDPTZ + +* Purpose: +* Find the number of decimal places and trailing zeros in a label. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int FindDPTZ( AstFrame *fr, int axis, const char *fmt, +* const char *text, int *ndp, int *ntz, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* The supplied label is split into fields using the astFields method of +* the supplied frame. The number of decimal places in the last +* field is returned in *ndp, and the total number of trailing zeros +* (excluding exponents) is returned in *ntz. + +* Parameters: +* fr +* The frame. +* axis +* The axis index to which the label applies. +* fmt +* The format string used to format the label. +* text +* The text of the label. +* ndp +* Pointer to an int in which to return the number of decimal +* places in the final field. +* ntz +* Pointer to an int in which to return the number of trailing zeros. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Non-zero if and only if a non-zero digit is found in any field. + +*/ + +/* Local Constants: */ +#define MAXFLD 10 + +/* Local Variables: */ + char *fields[ MAXFLD ]; + const char *a; + const char *dot; + const char *ff; + double junk; + int fnc; + int i; + int j; + int l; + int mxnd; + int nc[ MAXFLD ]; + int nf; + int result; + +/* Initialise */ + *ndp = 0; + *ntz = 0; + result = 0; + +/* Check inherited status */ + if( !astOK ) return result; + +/* Split the label up into fields. */ + nf = astFields( fr, axis, fmt, text, MAXFLD, fields, nc, &junk ); + if( nf > 0 ) { + +/* Search the last fields (assumed to be the least significant) for a + decimal point. */ + ff = fields[ nf - 1 ]; + fnc = nc[ nf - 1 ]; + dot = strchr( ff, '.' ); + if( dot && ( ff - dot >= fnc ) ) dot = NULL; + +/* Find the number of digits following the decimal point. */ + if( dot ) { + *ndp = strspn( dot + 1, "0123456789" ); + mxnd = fnc - ( dot - ff ) - 1; + if( *ndp > mxnd ) *ndp = mxnd; + } else { + *ndp = 0; + } + +/* Loop through all the fields, from least significant to most significant, + counting the number of trailing zeros. */ + *ntz = 0; + for( i = nf - 1; i >= 0; i-- ) { + l = strspn( fields[ i ], "-+0123456789." ); + if( l > nc[ i ] ) l = nc[ i ]; + a = fields[ i ] + l - 1; + for( j = l - 1; j >= 0; j--,a-- ){ + if( *a == '0' ) { + (*ntz)++; + } else if( isdigit( *a ) ) { + result = 1; + break; + } + } + if( j >= 0 ) break; + } + } + +/* Return the result. */ + return result; + +/* Undefine local constants: */ +#undef MAXFLD + +} + +static int FindString( int n, const char *list[], const char *test, + const char *text, const char *method, + const char *class, int *status ){ +/* +* Name: +* FindString + +* Purpose: +* Find a given string within an array of character strings. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int FindString( int n, const char *list[], const char *test, +* const char *text, const char *method, const char *class, +* int *status ) + +* Class Membership: +* Plot method. + +* Description: +* This function identifies a supplied string within a supplied +* array of valid strings, and returns the index of the string within +* the array. The test option may not be abbreviated, but case is +* insignificant. + +* Parameters: +* n +* The number of strings in the array pointed to be "list". +* list +* A pointer to an array of legal character strings. +* test +* A candidate string. +* text +* A string giving a description of the object, parameter, +* attribute, etc, to which the test value refers. +* This is only for use in constructing error messages. It should +* start with a lower case letter. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The index of the identified string within the supplied array, starting +* at zero. + +* Notes: +* - A value of -1 is returned if an error has already occurred, or +* if this function should fail for any reason (for instance if the +* supplied option is not specified in the supplied list). + +*/ + +/* Local Variables: */ + int ret; /* The returned index */ + +/* Check global status. */ + if( !astOK ) return -1; + +/* Compare the test string with each element of the supplied list. Leave + the loop when a match is found. */ + for( ret = 0; ret < n; ret++ ) { + if( !Ustrcmp( test, list[ ret ], status ) ) break; + } + +/* Report an error if the supplied test string does not match any element + in the supplied list. */ + if( ret >= n ) { + astError( AST__OPT, "%s(%s): Illegal value '%s' supplied for %s.", status, + method, class, test, text ); + ret = -1; + } + +/* Return the answer. */ + return ret; +} + +static char *FindWord( char *ptr, const char *d, const char **p, int *status ) { +/* +* Name: +* FindWord + +* Purpose: +* Return a copy of the next word in a supplied string. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* char *FindWord( char *ptr, const char *d, const char **p, int *status ) + +* Class Membership: +* Plot method. + +* Description: +* This function locates the start and end of the first word in the +* string pointed to by *p, and returns a copy of the word. The pointer +* *p is modified to point to the start of the following word (if any). +* The characters which delimit words are supplied in string "d". + +* Parameters: +* ptr +* A pointer to a character string in which to store the returned +* word. The memory holding this string should have been allocated +* using one of the functions in the AST "memory" module. The memory +* area will be modified in size to fit the returned word. A NULL +* pointer may be supplied if no memory has yet been allocated. +* Any memory pointed to by ptr is freed if a NULL pointer is +* returned by this function (i.e. if no word is found). +* d +* A string holding the characters which are to be used as word +* delimiters. +* p +* The address of a character string pointer. On entry, this pointer +* identifies the start of the string to be searched. On exit, it is +* modified to point to the start of the following word. It is +* returned NULL if there are no more words. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to a dynamically allocated character string holding the +* next word, or NULL if no word could be found. + +*/ + +/* Local Variables: */ + const char *a, *b, *c; + char *ret; + int nc; + +/* Free any allocated memory and return if any of the supplied pointers + (except ptr) is NULL, or if an error has occurred. */ + if( !astOK || !d || !p || !*p ) { + (void) astFree( (void *) ptr ); + return NULL; + } + +/* Get a pointer to the first character which is not in "d". Terminate + the loop if a null character is encountered. */ + a = *p; + while( *a && strchr( d, (int) *a ) ) a++; + +/* Get a pointer to the next character which is in "d". Terminate + the loop if a null character is encountered. */ + b = a; + while( *b && !strchr( d, (int) *b ) ) b++; + +/* Get a pointer to the next character which is not in "d". Terminate + the loop if a null character is encountered. */ + c = b; + while( *c && strchr( d, (int) *c ) ) c++; + +/* Adjust the supplied pointer so that it points to the start of the next + word. */ + if( *c ){ + *p = c; + } else { + *p = NULL; + } + +/* Get a null-terminated copy of the word between a and b. */ + nc = b - a; + if( nc > 0 ) { + ret = (char *) astStore( (void *) ptr, (void *) a, (size_t) (nc + 1) ); + ret[ nc ] = 0; + } else { + ret = astFree( (void *) ptr ); + } + + return ret; +} + +static const char *SplitValue( AstPlot *this, const char *value, int axis, + int *split, int *status ) { +/* +* Name: +* FormatValue + +* Purpose: +* Format a coordinate value for a Frame axis. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* const char *SplitValue( AstPlot *this, const char *value, +* int axis, int *split ) + +* Class Membership: +* Plot member function + +* Description: +* This function splits long formatted values (such as the date/time +* format produced by the TimeFrame class) if possible onto two lines +* by inclusion of Plot escape sequences. + +* Parameters: +* this +* Pointer to the Plot. +* value +* The formatted coordinate value. +* axis +* Indicates whether or not short lines should be split by +* including a blank first line. If zero, and if "*split" is non-zero, +* then short lines are put onto the second line,and the first line +* is blank. +* split +* Pointer to an integer that controls behaviour: +* +* 0 - Split the line if it is too long, and return a value of +1 +* in *split. +* 1 - Split the line even if it does not need splitting, making +* the first line blank and the second line containing all the +* supplied text (*split is unchanged on exit). + +* Returned Value: +* A pointer to a static buffer containing a null-terminated string +* holding the (possibly split) formatted value. This will be a copy of +* the supplied pointer if the string does not need to be split. + +* Notes: +* - A NULL pointer will be returned if this function is invoked with the +* global error status set, or if it should fail for any reason. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS + char *d; + const char *result; + float rsp; + int aft_end; + int aft_start; + int bef_end; + int bef_start; + int i; + int id; + int idmin; + int imin; + int l; + int naft; + int nbef; + int nlong; + int nshort; + int nsp; + +/* Initialise */ + result = value; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Do nothing more if the formatted value already contains graphical + escape sequences, or if graphical escapes sequences are not being + interpreted. */ + if( value && astGetEscape( this ) && !HasEscapes( value, status ) ) { + +/* Attempt to find a space close to the centre of the formatted string. */ + l = strlen( value ); + idmin = 2*l; + imin = -1; + for( i = 0; i < l; i++ ) { + if( isspace( value[ i ] ) ) { + id = abs( i - l/2 ); + if( id < idmin ) { + idmin = id; + imin = i; + } + } + } + +/* We split the line if previous lines have been split (i.e. if *split was + non-zero on entry) or if this line is long AND it contains a space. This + means that a sequence of long labels will not be split unless they contain + spaces. */ + if( *split || ( l > 9 && imin != -1 ) ) { + *split = 1; + +/* Initialse the pointer into the returned buffer at which the next + character will be placed. */ + d = splitvalue_buff; + +/* If no spaces were found... */ + if( imin == -1 ) { + +/* If axis is zero, we add a blank first line. */ + if( axis == 0 ) { + +/* Fill the first line with spaces. */ + for( i = 0; i < l; i++ ) *(d++) = ' '; + +/* Add an escape sequence that moves down by one character height. */ + d += sprintf( d, "%%v170+" ); + } + +/* Add the whole of the supplied text. */ + for( i = 0; i < l; i++ ) *(d++) = value[ i ]; + +/* If a space was found... */ + } else { + +/* Find the first and last non-blank characters before the mid-space. */ + bef_start = -1; + bef_end = -1; + for( i = 0; i < imin; i++ ) { + if( !isspace( value[ i ] ) ) { + if( bef_start == -1 ) bef_start = i; + bef_end = i; + } + } + +/* Find the first and last non-blank characters after the mid-space. */ + aft_start = -1; + aft_end = -1; + for( i = imin + 1; i < l; i++ ) { + if( !isspace( value[ i ] ) ) { + if( aft_start == -1 ) aft_start = i; + aft_end = i; + } + } + +/* How many significant characters before and after the space? */ + nbef = bef_end - bef_start + 1; + naft = aft_end - aft_start + 1; + +/* Get the lengths of the longer and shorter line. */ + if( nbef > naft ) { + nlong = nbef; + nshort = naft; + } else { + nlong = naft; + nshort = nbef; + } + +/* Find the fractional number of spaces before the significant text of the + shorter line.*/ + rsp = 0.5*( nlong - nshort + 1 ); + +/* If the top line is the shorter line, put some spaces in at the start. */ + if( nbef < naft ) { + nsp = (int) rsp; + for( i = 0; i < nsp; i++ ) *(d++) = ' '; + } + +/* Add the significant text from the top line. */ + for( i = bef_start; i <= bef_end; i++ ) *(d++) = value[ i ]; + +/* Add an escape sequence that moves down by one character height. */ + d += sprintf( d, "%%v100+" ); + + +/* Add an escape sequence that moves to the left by the required amount. */ + d += sprintf( d, "%%<%d+", (int) ( 60.0*( (float) nlong - rsp )) ); + +/* Add the significant text from the bottom line. */ + for( i = aft_start; i <= aft_end; i++ ) *(d++) = value[ i ]; + + } + +/* Terminate it. */ + *d = 0; + +/* Return a pointer to the buffer. */ + result = splitvalue_buff; + } + } + +/* If an error occurred, clear the returned value. */ + if ( !astOK ) result = NULL; + +/* Return the result. */ + return result; +} + +static void Fpoly( AstPlot *this, const char *method, const char *class, + int *status ){ +/* +* Name: +* Fpoly + +* Purpose: +* Flush all stored poly lines to the graphics system. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Fpoly( AstPlot *this, const char *method, const char *class, +* int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function sends all previously drawn poly lines to the graphics +* system for rendering, and frees the memory used to hold the poly +* lines. It attempts to reduce the number of graphics calls by +* concatenating continuous polylines together. + +* Parameters: +* this +* Pointer to the Plot. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS + float xmid; + float xt; + float ymid; + float *xnew; + float *ynew; + int polylen; + float *xp1; + float *xp2; + float *yp1; + float *yp2; + float yt; + int *ekey; + int *p; + int *skey; + int *drawn; + int ihi; + int ikey; + int ilo; + int imid; + int ipass; + int ipoint; + int ipoly; + int jpoly; + int kpoly; + int *polylist; + int npoly; + int np; + +/* Check the global status. */ + if( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Output any pending polyline. */ + Opoly( this, status ); + +/* If there is just one polyline to output, just draw it and then free + the memory used to hold the polyline. */ + if( Poly_npoly == 1 ) { + GLine( this, Poly_np[ 0 ], Poly_xp[ 0 ], Poly_yp[ 0 ], method, class, + status ); + Poly_xp[ 0 ] = astFree( Poly_xp[ 0 ] ); + Poly_yp[ 0 ] = astFree( Poly_yp[ 0 ] ); + Poly_np[ 0 ] = 0; + +/* If there are multiple polylines to output, see if any of them can be + combined before drawing them. */ + } else if( Poly_npoly > 1 ) { + +/* No polyline buffer allocated yet. */ + xnew = NULL; + ynew = NULL; + +/* Allocate an array to hold the order in which polylines should be + concatenated. Each value in this array will be the index of one of the + original polylines. A positive index indicates that the polyline + should be appended in its original order. A negative index indicates + that the polyline should be appended in reversed order. Polyline zero + is always appended in its original order. */ + polylist = astMalloc( Poly_npoly*sizeof( int ) ); + npoly = 0; + +/* Create an array of drawn, one for each individual polyline. The flag + is zero if the corresponding polyline has not yet been drawn. */ + drawn = astCalloc( Poly_npoly, sizeof( int ) ); + +/* Create two sorted keys for the polylines - one that sorts them into + increasing x at the start of the polyline, and another that sorts them + into increasing x at the end of the polyline. */ + skey = astMalloc( Poly_npoly*sizeof( int ) ); + ekey = astMalloc( Poly_npoly*sizeof( int ) ); + if( astOK ) { + + p = skey; + for( ipoly = 0; ipoly < Poly_npoly; ipoly++ ) *(p++) = ipoly; + qsort( skey, Poly_npoly, sizeof(int), Fpoly_scmp ); + + p = ekey; + for( ipoly = 0; ipoly < Poly_npoly; ipoly++ ) *(p++) = ipoly; + qsort( ekey, Poly_npoly, sizeof(int), Fpoly_ecmp ); + + } + +/* Continue to search for separate polylines that can be combined together + until we know there are no more. */ + while( astOK ) { + +/* Search for the first polyline that has not already been drawn. */ + for( ipoly = 0; ipoly < Poly_npoly; ipoly++ ) { + if( !drawn[ ipoly ] ) break; + } + +/* Leave the loop if no more polylines remain to be plotted. */ + if( ipoly == Poly_npoly ) break; + +/* Initialise the list of polylines to hold the polyline found above, in + its forward sense. */ + polylist[ 0 ] = ipoly; + npoly = 1; + drawn[ 0 ] = 1; + +/* Initialise the concatenation point to be the end of the polyline found + above. Also, initialise the total number of points in the combined + polyline (polylen). */ + ipoint = Poly_np[ ipoly ] - 1; + xt = Poly_xp[ ipoly ][ ipoint ]; + yt = Poly_yp[ ipoly ][ ipoint ]; + polylen = ipoint + 1; + +/* Loop until we can find no more polylines to append to the list. + A polyline can be appended if it starts or ends at the current + concatenation point. */ + while( astOK ) { + +/* On the first pass through the next loop, search for a polyline that + starts at the concatenation point. If no such polyline is found, do + a second pass in which we search for a polyline that ends at the + concatenation point. Do not include any previously drawn polylines + in the search. */ + for( ipass = 0; ipass < 2; ipass++ ) { + +/* We use a binary chop to find a polyline which starts (or ends) at the + x value of the concatenation point. */ + jpoly = -1; + ilo = 0; + ihi = Poly_npoly - 1; + while( 1 ) { + imid = ( ilo + ihi )/2; + if( ipass == 0 ) { + jpoly = skey[ imid ]; + xmid = Poly_xp[ jpoly ][ 0 ]; + } else { + jpoly = ekey[ imid ]; + xmid = Poly_xp[ jpoly ][ Poly_np[ jpoly ] - 1 ]; + } + if( astEQUALS( xmid, xt, 1.0E8 ) ) { + ikey = imid; + break; + } else if( xmid > xt ) { + if( ihi == imid ) { + if( ipass == 0 ) { + jpoly = skey[ ilo ]; + xmid = Poly_xp[ jpoly ][ 0 ]; + } else { + jpoly = ekey[ ilo ]; + xmid = Poly_xp[ jpoly ][ Poly_np[ jpoly ] - 1 ]; + } + if( !astEQUALS( xmid, xt, 1.0E8 ) ) jpoly = -1; + ikey = ilo; + break; + } + ihi = imid; + } else { + if( ilo == imid ) { + if( ipass == 0 ) { + jpoly = skey[ ihi ]; + xmid = Poly_xp[ jpoly ][ 0 ]; + } else { + jpoly = ekey[ ihi ]; + xmid = Poly_xp[ jpoly ][ Poly_np[ jpoly ] - 1 ]; + } + if( !astEQUALS( xmid, xt, 1.0E8 ) ) jpoly = -1; + ikey = ihi; + break; + } + ilo = imid; + } + } + +/* If found, there may be more than one such polyline. So we now search + for a polyline that also has the y value of the concatenation point. */ + if( jpoly != -1 ) { + +/* If the polyline found above starts (or ends) at the same Y value as the + concatenation point, then we have found the required polyline. */ + if( ipass == 0 ) { + ymid = Poly_yp[ jpoly ][ 0 ]; + } else { + ymid = Poly_yp[ jpoly ][ Poly_np[ jpoly ] - 1 ]; + } + if( astEQUALS( ymid, yt, 1.0E8 ) && !drawn[ jpoly ] ) break; + jpoly = -1; + +/* Otherwise, search down the list, starting at the polyline found above. */ + if( imid > 0 ) { + for( ikey = imid - 1; ikey >= 0; ikey-- ) { + if( ipass == 0 ) { + kpoly = skey[ ikey ]; + xmid = Poly_xp[ kpoly ][ 0 ]; + ymid = Poly_yp[ kpoly ][ 0 ]; + } else { + kpoly = ekey[ ikey ]; + xmid = Poly_xp[ kpoly ][ Poly_np[ kpoly ] - 1 ]; + ymid = Poly_yp[ kpoly ][ Poly_np[ kpoly ] - 1 ]; + } + if( astEQUALS( xmid, xt, 1.0E8 ) ) { + if( astEQUALS( ymid, yt, 1.0E8 ) && !drawn[ kpoly ] ) { + jpoly = kpoly; + break; + } + } else { + break; + } + } + if( jpoly != -1 ) break; + } + +/* Now search up the list, starting at the polyline found above. */ + if( imid < Poly_npoly - 1 ) { + for( ikey = imid + 1; ikey < Poly_npoly; ikey++ ) { + if( ipass == 0 ) { + kpoly = skey[ ikey ]; + xmid = Poly_xp[ kpoly ][ 0 ]; + ymid = Poly_yp[ kpoly ][ 0 ]; + } else { + kpoly = ekey[ ikey ]; + xmid = Poly_xp[ kpoly ][ Poly_np[ kpoly ] - 1 ]; + ymid = Poly_yp[ kpoly ][ Poly_np[ kpoly ] - 1 ]; + } + if( astEQUALS( xmid, xt, 1.0E8 ) ) { + if( astEQUALS( ymid, yt, 1.0E8 ) && !drawn[ kpoly ] ) { + jpoly = kpoly; + break; + } + } else { + break; + } + } + if( jpoly != -1 ) break; + } + } + } + +/* If a polyline was found that can be combined with the total polyline, + increment the total number of points in the total polyline, add it to + the list, and update the concatenation point. Note, we can omit the + start or end point of the new polyline since it will already be + present in the total polyline, hence the " - 1 " below. */ + if( ipass < 2 ) { + ipoint = Poly_np[ jpoly ] - 1; + + if( ipass == 0 ) { + polylist[ npoly++ ] = jpoly; + xt = Poly_xp[ jpoly ][ ipoint ]; + yt = Poly_yp[ jpoly ][ ipoint ]; + } else { + polylist[ npoly++ ] = -jpoly; + xt = Poly_xp[ jpoly ][ 0 ]; + yt = Poly_yp[ jpoly ][ 0 ]; + } + + polylen += ipoint; + +/* Indicate the polyline has been drawn. */ + drawn[ jpoly ] = 1; + +/* If we cannot find any polyline that starts or ends at the + concatenation point, then we have completed the total polyline. So break + out of the loop, and move on to draw the total polyline. */ + } else { + break; + } + } + +/* If a single polyline is to be drawn, just draw it. */ + if( npoly == 1 ) { + jpoly = polylist[ 0 ]; + GLine( this, Poly_np[ jpoly ], Poly_xp[ jpoly ], + Poly_yp[ jpoly ], method, class, status ); + +/* If more than one polyline is to be drawn, ensure we have arrays that + are large enough to hold all the vertices in the combined polyline. */ + } else { + xnew = astRealloc( xnew, polylen*sizeof( float ) ); + ynew = astRealloc( ynew, polylen*sizeof( float ) ); + if( astOK ) { + +/* Loop round all the polylines that are to be combined to form the total + polyline, and copy all the vertex coordinates into the above arrays. */ + xp1 = xnew; + yp1 = ynew; + for( ipoly = 0; ipoly < npoly; ipoly++ ) { + +/* Index of the next polyline to include in the total polyline. */ + jpoly = polylist[ ipoly ]; + +/* The jpoly value is positive if the polylline is to be inclued in its + original direction. */ + if( jpoly >= 0 ) { + +/* Use the whole of the first polyline. */ + if( ipoly == 0 ) { + np = Poly_np[ jpoly ]; + xp2 = Poly_xp[ jpoly ]; + yp2 = Poly_yp[ jpoly ]; + +/* Omit eh first point of subsequent polylines since it will be the same + as the last pointy already in the total polyline. */ + } else { + np = Poly_np[ jpoly ] - 1; + xp2 = Poly_xp[ jpoly ] + 1; + yp2 = Poly_yp[ jpoly ] + 1; + } + +/* Copy the vertex values in their original order, and update the + pointers to the next element of the total polyline. */ + memcpy( xp1, xp2, np*sizeof(float) ); + memcpy( yp1, yp2, np*sizeof(float) ); + xp1 += np; + yp1 += np; + +/* The jpoly value is negative if the polyline is to be included in its + reversed direction. */ + } else { + jpoly = -jpoly; + +/* Get the number of points to copy. Omit the last point if this is not + the first polyline, since it is already in the total polyline. */ + if( ipoly == 0 ) { + np = Poly_np[ jpoly ]; + } else { + np = Poly_np[ jpoly ] - 1; + } + +/* Copy the individual values in reversed order. */ + xp2 = Poly_xp[ jpoly ] + np - 1; + yp2 = Poly_yp[ jpoly ] + np - 1; + for( ipoint = 0; ipoint < np; ipoint++ ) { + *(xp1++) = *(xp2--); + *(yp1++) = *(yp2--); + } + } + } + +/* And finally, draw the total polyline. */ + GLine( this, polylen, xnew, ynew, method, class, status ); + } + } + } + +/* Free all the individual polylines. */ + for( ipoly = 0; ipoly < Poly_npoly; ipoly++ ) { + Poly_xp[ ipoly ] = astFree( Poly_xp[ ipoly ] ); + Poly_yp[ ipoly ] = astFree( Poly_yp[ ipoly ] ); + Poly_np[ ipoly ] = 0; + } + +/* Free other resources. */ + polylist = astFree( polylist ); + drawn = astFree( drawn ); + xnew = astFree( xnew ); + ynew = astFree( ynew ); + skey = astFree( skey ); + ekey = astFree( ekey ); + } + +/* Indicate that all polylines have been sent to the graphics system. */ + Poly_npoly = 0; +} + +static int Fpoly_ecmp( const void *a, const void *b ){ +/* +* Name: +* Fpoly_ecmp + +* Purpose: +* Compare two polylines ending X position + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int Fpoly_ecmp( const void *a, const void *b ) + +* Class Membership: +* Plot member function. + +* Description: +* This function is designed to be used as a comparison function with +* the "qsort" function. It is used in function Fpoly. +* +* If orders the two polylines on the basis of the X coordinate at +* their ends. + +* Parameters: +* a +* Pointer to an int holding the index of the first polyline. +* b +* Pointer to an int holding the index of the second polyline. + +* Returned Value: +* -1 if the first polyline ends at a lower X than the second. +* +1 if the first polyline ends at a higher X than the second. +* 0 if the two polylines end at the same X. + +*/ + +/* Local Variables: */ + float xa; /* X at end of first polyline */ + float xb; /* X at end of second polyline */ + int result = 0; /* Returned value */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Get the x coord at the end of the two polylines. */ + xa = Poly_xp[ *( (int *) a) ][ Poly_np[ *( (int *) a) ] - 1 ]; + xb = Poly_xp[ *( (int *) b) ][ Poly_np[ *( (int *) b) ] - 1 ]; + +/* Compare them. */ + if( xa < xb ) { + result = -1; + } else if( xa > xb ){ + result = 1; + } + + return result; +} + +static int Fpoly_scmp( const void *a, const void *b ){ +/* +* Name: +* Fpoly_scmp + +* Purpose: +* Compare two polylines starting X position + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int Fpoly_scmp( const void *a, const void *b ) + +* Class Membership: +* Plot member function. + +* Description: +* This function is designed to be used as a comparison function with +* the "qsort" function. It is used in function Fpoly. +* +* If orders the two polylines on the basis of the X coordinate at +* their starts. + +* Parameters: +* a +* Pointer to an int holding the index of the first polyline. +* b +* Pointer to an int holding the index of the second polyline. + +* Returned Value: +* -1 if the first polyline starts at a lower X than the second. +* +1 if the first polyline starts at a higher X than the second. +* 0 if the two polylines starts at the same X. + +*/ + +/* Local Variables: */ + float xa; /* X at start of first polyline */ + float xb; /* X at start of second polyline */ + int result = 0; /* Returned value */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Get the x coord at the start of the two polylines. */ + xa = Poly_xp[ *( (int *) a) ][ 0 ]; + xb = Poly_xp[ *( (int *) b) ][ 0 ]; + +/* Compare them. */ + if( xa < xb ) { + result = -1; + } else if( xa > xb ){ + result = 1; + } + + return result; +} + +static AstFrameSet *Fset2D( AstFrameSet *fset, int ifrm, int *status ) { +/* +* Name: +* Fset2D + +* Purpose: +* Create a FrameSet with no more than 2 dimensions for a given Frame. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* AstFrameSet *Fset2D( AstFrameSet *fset, int ifrm, int *status ) + +* Class Membership: +* Plot method. + +* Description: +* This function checks a specified Frame in the supplied FrameSet. +* If the Frame has more than 2 dimensions, a new Frame is added to +* the FrameSet containing just the first two axes of the specified +* Frame. A PermMap is used to connect this Frame to the specified +* Frame, which supplied bad values for any missing axes. If the +* specified Frame is the base Frame in the supplied FrameSet, then the +* new Frame becomes the base Frame in the returned FrameSet. Like-wise, +* if the specified Frame is the current Frame, then the new Frame +* will be the current Frame in the returned FrameSet. +* +* If the specified Frame does not have more than 2 axes, then a clone +* of the FrameSet pointer is returned, otherwise the returned pointer +* points to a copy of the supplied FrameSet with the new 2-D Frame +* added. + +* Parameters: +* fset +* Pointer to the FrameSet. +* ifrm +* The index of the Frame to check. This should be AST__BASE or +* AST_CURRENT. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to a FrameSet in which the Frame with index given by ifrm +* has no more than 2 axes. +*/ + +/* Local Variables: */ + AstFrame *frm; + AstFrame *newfrm; + AstFrameSet *ret; + AstPermMap *map; + double zero; + int *inperm; + int axes[2]; + int i; + int ic; + int nax; + +/* Check the inherited status. */ + if( !astOK ) return NULL; + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + map = NULL; + +/* Get a pointer to the requested Frame in the supplied FrameSet. */ + frm = astGetFrame( fset, ifrm ); + +/* See how many dimensions the specified Frame of the supplied FrameSet + has. */ + nax = astGetNaxes( frm ); + +/* If it is more than 2-dimensionbal, create a 2D Frame by picking + axes 1 and 2 from the original Frame. */ + if( nax > 2 ) { + axes[ 0 ] = 0; + axes[ 1 ] = 1; + newfrm = astPickAxes( frm, 2, axes, NULL ); + +/* Create a PermMap to describe the mapping between the two Frames. + Use zero as the value for unknown axes (the optional mapping which + can be returned by astPickAxes uses AST__BAD for unknown axes). */ + inperm = (int *) astMalloc( sizeof(int)*(size_t) nax ); + if( astOK ){ + inperm[ 0 ] = 0; + inperm[ 1 ] = 1; + for( i = 2; i < nax; i++ ) inperm[ i ] = -1; + zero = 0.0; + map = astPermMap( nax, inperm, 2, axes, &zero, "", status ); + inperm = (int *) astFree( (void *) inperm ); + } + +/* Get a copy of the supplied FrameSet. */ + ret = astCopy( fset ); + +/* Add the new Frame to the FrameSet (it becomes the current Frame). */ + ic = astGetCurrent( ret ); + astAddFrame( ret, ifrm, map, newfrm ); + newfrm = astAnnul( newfrm ); + +/* If the new Frame was derived from the base frame, set the new base + Frame, and re-instate the original current Frame */ + if( ifrm == AST__BASE ){ + astSetBase( ret, astGetCurrent( ret ) ); + astSetCurrent( ret, ic ); + } + +/* If the specified Frame in the supplied FrameSet is 2-dimensional, just + return a clone of it. */ + } else { + ret = astClone( fset ); + } + +/* Annul the pointer to the original Frame. */ + frm = astAnnul( frm ); + + return ret; + +} + +static int FullForm( const char *list, const char *test, const char *text, + const char *method, const char *class, int *status ){ +/* +* Name: +* FullForm + +* Purpose: +* Identify the full form of an option string. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int FullForm( const char *list, const char *test, const char *text, +* const char *method, const char *class, int *status ) + +* Class Membership: +* Plot method. + +* Description: +* This function identifies a supplied test option within a supplied +* list of valid options, and returns the index of the option within +* the list. The test option may be abbreviated, and case is +* insignificant. + +* Parameters: +* list +* A list of space separated option strings. +* test +* A candidate option string. +* text +* A string giving the context in which the supplied test option +* was supplied. For instance, this may be an attribute setting string. +* This is only for use in constructing error messages. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The index of the identified option within the supplied list, starting +* at zero. + +* Notes: +* - A value of -1 is returned if an error has already occurred, or +* if this function should fail for any reason (for instance if the +* supplied option is not uniquely specified in the supplied list). + +*/ + +/* Local Variables: */ + char *option; /* Pointer to a copy of the next option */ + const char *p; /* Pointer to the start of the next word */ + int i; /* Current option index */ + int len; /* Length of supplied option */ + int nmatch; /* Number of matching options */ + int ret; /* The returned index */ + +/* Initialise the answer to indicate that the option has not been + uniquely identified. */ + ret = -1; + +/* Check global status. */ + if( !astOK ) return ret; + +/* Save the number of characters in the supplied test option (excluding + trailing spaces). */ + len = ChrLen( test, status ); + +/* Compare the supplied test option against each of the known options in + turn. Count the number of matches. */ + nmatch = 0; + p = list; + option = FindWord( NULL, " ", &p, status ); + i = 0; + while( option ){ + +/* If the test string and the current option are identical (including + length). use the current option. */ + +/* If every character in the supplied label matches the corresponding + character in the current test label we have a match. Increment the + number of matches and save the current item index. If the test string + and the current option are identical (including length), use the + current option. */ + + if( !Ustrncmp( test, option, len, status ) ) { + ret = i; + if( ChrLen( option, status ) == len ) { + nmatch = 1; + option = astFree( option ); + break; + } else { + nmatch++; + } + } + +/* Get a pointer to the next option. */ + option = FindWord( option, " ", &p, status ); + i++; + } + +/* Report an error if no match was found, and return -1. */ + if( !nmatch ){ + astError( AST__OPT, "%s(%s): Option '%.*s' is unknown in '%.*s'.", status, + method, class, len, test, ChrLen( text, status ), text ); + ret = -1; + +/* Report an error if the label was ambiguous, and return -1. */ + } else if( nmatch > 1 ){ + astError( AST__OPT, "%s(%s): Option '%.*s' is ambiguous in '%.*s'.", status, + method, class, len, test, ChrLen( text, status ), text ); + ret = -1; + } + +/* Return the answer. */ + return ret; +} + +static void GAttr( AstPlot *this, int attr, double value, double *old_value, + int prim, const char *method, const char *class, int *status ) { +/* +* +* Name: +* GAttr + +* Purpose: +* Call the GAttr Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void GAttr( AstPlot *this, int attr, double value, double *old_value, +* int prim, const char *method, const char *class, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* This function calls the GAttr grf function to enquire or set a +* graphics attribute value. It either calls the version registered using +* astGrfSet, or the version in the linked grf module. The linked version +* is used if the Grf attribute is zero, or if no function has been +* registered for GAttr using astGrfSet. + +* Parameters: +* this +* The Plot. +* attr +* An integer value identifying the required attribute. The +* following symbolic values are defined in grf.h: +* +* GRF__STYLE - Line style. +* GRF__WIDTH - Line width. +* GRF__SIZE - Character and marker size scale factor. +* GRF__FONT - Character font. +* GRF__COLOUR - Colour index. +* value +* A new value to store for the attribute. If this is AST__BAD +* no value is stored. +* old_value +* A pointer to a double in which to return the attribute value. +* If this is NULL, no value is returned. +* prim +* The sort of graphics primitive to be drawn with the new attribute. +* Identified by the following values defined in grf.h: +* GRF__LINE +* GRF__MARK +* GRF__TEXT +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + int grf_status; /* Status retruned from Grf function */ + +/* Check the global error status. Also return if there is nothing to do. */ + if ( !astOK || ( !old_value && value == AST__BAD ) ) return; + +/* Since we are about to call an external function which may not be + thread safe, prevent any other thread from executing the following code + until the current thread has finished executing it. */ + LOCK_MUTEX2; + +/* If the Grf attribute is set to a non-zero value, use the Grf function + registered using astGrfSet (so long as a function has been supplied). + This called via a wrapper which adapts the interface to suit the + language in which the function is written. */ + if( astGetGrf( this ) && this->grffun[ AST__GATTR ] ) { + grf_status = ( *( this->GAttr ) )( this, attr, value, old_value, prim, status ); + +/* Otherwise, use the function in the external Grf module, selected at + link-time using ast_link options.*/ + } else { + grf_status = astGAttr( attr, value, old_value, prim ); + } + +/* Allow the next thread to proceed. */ + UNLOCK_MUTEX2; + +/* Report an error if anything went wrong. */ + if( !grf_status ) { + astError( AST__GRFER, "%s(%s): Graphics error in astGAttr. ", status, method, + class ); + } + +} + +static AstKeyMap *GetGrfContext( AstPlot *this, int *status ){ +/* +*++ +* Name: +c astGetGrfContext +f AST_GETGRFCONTEXT + +* Purpose: +* Return the KeyMap that describes a Plot's graphics context. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "plot.h" +c AstKeyMap *astGetGrfContext( AstPlot *this ) +f RESULT = AST_GETGRFCONTEXT( THIS, STATUS ) + +* Class Membership: +* Plot method. + +* Description: +c This function +f This routine +* returns a reference to a KeyMap that will be passed to any drawing +c functions registered using astGrfSet. +f routines registered using AST_GRFSET. +* This KeyMap can be used by an application to pass information to +c the drawing functions +f the drawing routines +* about the context in which they are being called. The contents of +* the KeyMap are never accessed byt the Plot class itself. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Returned Value: +c astGetGrfContext() +f AST_GETGRFCONTEXT = INTEGER +* A pointer to the graphics context KeyMap. The returned pointer +* should be annulled when it is no longer needed. + +*-- +*/ + +/* Check the global error status. */ + if ( !astOK ) return NULL; + +/* Ensure that a grfcon KeyMap exists. */ + (void) astGrfConID(this); + +/* Return a cloned pointer to the KeyMap. */ + return astClone( this->grfcontext ); +} + +AstKeyMap *astGrfConID_( AstPlot *this, int *status ) { +/* +*+ +* +* Name: +* astGrfConID + +* Purpose: +* Ensure a GrfContext KeyMap exists and return an ID for it. + +* Type: +* Protected function. + +* Synopsis: +* #include "plot.h" +* AstKeyMap *astGrfConID( AstPlot *this ) + +* Class Membership: +* Plot private function. + +* Description: +* This function creates a GrfContext KeyMap if the Plot does not +* currently have one, and returns an ID for it. + +* Parameters: +* this +* The Plot. + +* Returned Value: +* ID for the GrfContext KeyMap. + +*- +*/ + if( !this->grfcontext ) { + this->grfcontext = astKeyMap("", status ); + this->grfcontextID = astMakeId( astClone( this->grfcontext ) ); + astExempt( this->grfcontextID ); + } + return this->grfcontextID; +} + +static void GScales( AstPlot *this, float *alpha, float *beta, + const char *method, const char *class, int *status ) { +/* +* +* Name: +* GScales + +* Purpose: +* Call the GScales Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void GScales( AstPlot *this, float *alpha, float *beta, +* const char *method, const char *class, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* This function calls the GScales grf function, either calling the +* version registered using astGrfSet, or the version in the linked grf +* module. The linked version is used if the Grf attribute is zero, or if +* no function has been registered for GScales using astGrfSet. + +* Parameters: +* this +* The Plot. +* alpha +* A pointer to the location at which to return the scale for the +* X axis (i.e. Xnorm = alpha*Xworld). +* beta +* A pointer to the location at which to return the scale for the +* Y axis (i.e. Ynorm = beta*Yworld). +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + int grf_status; /* Status retruned from Grf function */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* if we already have the required values, return them. */ + if( Grf_alpha != 0.0 && Grf_beta != 0.0 ) { + if( alpha ) *alpha = Grf_alpha; + if( beta ) *beta = Grf_beta; + return; + } + +/* Check that the grf mdoule can give us scales information. */ + if( GCap( this, GRF__SCALES, 1, status ) ) { + +/* Since we are about to call an external function which may not be + thread safe, prevent any other thread from executing the following code + until the current thread has finished executing it. */ + LOCK_MUTEX2; + +/* If the Grf attribute is set to a non-zero value, use the Grf function + registered using astGrfSet (so long as a function has been supplied). + This is called via a wrapper which adapts the interface to suit the + language in which the function is written. */ + if( astGetGrf( this ) && this->grffun[ AST__GSCALES ] ) { + grf_status = ( *( this->GScales ) )( this, &Grf_alpha, &Grf_beta, status ); + +/* Otherwise, use the function in the external Grf module, selected at + link-time using ast_link options.*/ + } else { + grf_status = astGScales( &Grf_alpha, &Grf_beta ); + } + +/* Allow the next thread to proceed. */ + UNLOCK_MUTEX2; + +/* Check neither value is zero. */ + if( grf_status && ( Grf_alpha == 0.0 || Grf_beta == 0.0 ) ) { + astError( AST__GRFER, "astGScales: Returned axis scales are %g and %g " + "but zero is illegal!", status, Grf_alpha, Grf_beta ); + grf_status = 0; + } + +/* Report an error if anything went wrong, and return safe values. */ + if( !grf_status ) { + astError( AST__GRFER, "%s(%s): Graphics error in astGScales. ", status, method, + class ); + Grf_alpha = 1.0; + Grf_beta = 1.0; + } + +/* If the grf module is not capable of giving us scale information, then + just assume the the axes are equally scaled, except for any axis reversal + indicated in the supplied Plot. */ + } else { + Grf_alpha = ( this->xrev ) ? -1.0 : 1.0; + Grf_beta = ( this->yrev ) ? -1.0 : 1.0; + } + +/* Store them for future use. */ + if( alpha ) *alpha = Grf_alpha; + if( beta ) *beta = Grf_beta; +} + +static int GCap( AstPlot *this, int cap, int value, int *status ){ +/* +* +* Name: +* GCap + +* Purpose: +* Call the GCap Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int GCap( AstPlot *this, int cap, int value, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* This function calls the GCap grf function to inquire a capability +* of the grf module, either calling the version registered using +* astGrfSet, or the version in the linked grf module. The linked +* version is used if the Grf attribute is zero, or if no function +* has been registered for GCap using astGrfSet. + +* Parameters: +* this +* The Plot. +* cap +* The capability to be inquired aboue. +* value +* The value ot assign to the capability. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Non-zero if the grf module is capabale of performing the action +* requested by "cap". + +*/ + +/* Local Variables: */ + int result; /* Value retruned from Grf function */ + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* Since we are about to call an external function which may not be + thread safe, prevent any other thread from executing the following code + until the current thread has finished executing it. */ + LOCK_MUTEX2; + +/* If the Grf attribute is set to a non-zero value, use the Grf function + registered using astGrfSet (so long as a function has been supplied). + This is called via a wrapper which adapts the interface to suit the + language in which the function is written. */ + if( astGetGrf( this ) && this->grffun[ AST__GCAP ] ) { + result = ( *( this->GCap ) )( this, cap, value, status ); + +/* Otherwise, use the function in the external Grf module, selected at + link-time using ast_link options.*/ + } else { + result = astGCap( cap, value ); + + } + +/* Allow the next thread to proceed. */ + UNLOCK_MUTEX2; + +/* Return the result. */ + return result; +} + +static void GenCurve( AstPlot *this, AstMapping *map, int *status ){ +/* +*++ +* Name: +c astGenCurve +f AST_GENCURVE + +* Purpose: +* Draw a generalized curve. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "plot.h" +c void astGenCurve( AstPlot *this, astMapping *map ) +f CALL AST_GENCURVE( THIS, MAP ) + +* Class Membership: +* Plot method. + +* Description: +c This function draws a general user-defined curve defined by the +f This routine draws a general user-defined curve defined by the +* supplied Mapping. Note that the curve is transformed into graphical +* coordinate space for plotting, so that a straight line in +* physical coordinates may result in a curved line being drawn if +* the Mapping involved is non-linear. Any discontinuities in the +* Mapping between physical and graphical coordinates are +c catered for, as is any clipping established using astClip. +f catered for, as is any clipping established using AST_CLIP. +* +c If you need to draw simple straight lines (geodesics), astCurve +c or astPolyCurve will usually be easier to use and faster. +f If you need to draw simple straight lines (geodesics), AST_CURVE +f or AST_POLYCURVE will usually be easier to use and faster. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +c map +f MAP = INTEGER (Given) +* Pointer to a Mapping. This Mapping should have 1 input +* coordinate representing offset along the required curve, +* normalized so that the start of the curve is at offset 0.0, +* and the end of the curve is at offset 1.0. Note, this offset +* does not need to be linearly related to distance along the curve. +* The number of output coordinates should equal the number of axes +* in the current Frame of the Plot. The Mapping should map a +* specified offset along the curve, into the corresponding +* coordinates in the current Frame of the Plot. The inverse +* transformation need not be defined. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +* - An error results if the base Frame of the Plot is not 2-dimensional. +* - An error also results if the transformation between the +* current and base Frames of the Plot is not defined (i.e. the +* Plot's TranInverse attribute is zero). +*-- +*/ +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + const char *class; /* Object class */ + const char *method; /* Current method */ + double d[ CRV_NPNT ]; /* Offsets to evenly spaced points along curve */ + double tol; /* Absolute tolerance value */ + double x[ CRV_NPNT ]; /* X coords at evenly spaced points along curve */ + double y[ CRV_NPNT ]; /* Y coords at evenly spaced points along curve */ + int i; /* Loop count */ + int naxes; /* No. of axes in the base Frame */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Store the current method, and the class of the supplied object for use + in error messages.*/ + method = "astGenCurve"; + class = astGetClass( this ); + +/* Check the base Frame of the Plot is 2-D. */ + naxes = astGetNin( this ); + if( naxes != 2 && astOK ){ + astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " + "Frame of the supplied %s is invalid - this number should " + "be 2.", status, method, class, naxes, class ); + } + +/* Only proceed if there has been no error. */ + if( astOK ){ + +/* Initialise the bounding box for primitives produced by this call. */ + if( !Boxp_freeze ) { + Boxp_lbnd[ 0 ] = FLT_MAX; + Boxp_lbnd[ 1 ] = FLT_MAX; + Boxp_ubnd[ 0 ] = FLT_MIN; + Boxp_ubnd[ 1 ] = FLT_MIN; + } + +/* Indicate that the GRF module should re-calculate it's cached values + (in case the state of the graphics system has changed since the last + thing was drawn). */ + RESET_GRF; + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + astGrfAttrs( this, AST__CURVE_ID, 1, GRF__LINE, method, class ); + +/* Ensure the globals holding the scaling from graphics coords to equally + scaled coords are available. */ + GScales( this, NULL, NULL, method, class, status ); + +/* Set up the externals used to communicate with the Map4 function... */ + Map4_ncoord = astGetNout( this ); + Map4_plot = this; + Map4_map = astGetMapping( this, AST__BASE, AST__CURRENT ); + Map4_umap = map; + +/* Convert the tolerance from relative to absolute graphics coordinates. */ + tol = astGetTol( this )*astMAX( this->xhi - this->xlo, + this->yhi - this->ylo ); + +/* Now set up the external variables used by the Crv and CrvLine function. */ + Crv_scerr = ( astGetLogPlot( this, 0 ) || + astGetLogPlot( this, 1 ) ) ? 100.0 : 1.5; + Crv_ux0 = AST__BAD; + Crv_tol = tol; + Crv_limit = 0.5*tol*tol; + Crv_map = Map4; + Crv_ink = 1; + Crv_xlo = this->xlo; + Crv_xhi = this->xhi; + Crv_ylo = this->ylo; + Crv_yhi = this->yhi; + Crv_out = 1; + Crv_xbrk = Curve_data.xbrk; + Crv_ybrk = Curve_data.ybrk; + Crv_vxbrk = Curve_data.vxbrk; + Crv_vybrk = Curve_data.vybrk; + Crv_clip = astGetClip( this ) & 1; + +/* Set up a list of points spread evenly over the curve. */ + for( i = 0; i < CRV_NPNT; i++ ){ + d[ i ] = ( (double) i)/( (double) CRV_NSEG ); + } + +/* Map these points into graphics coordinates. */ + Map4( CRV_NPNT, d, x, y, method, class, status GLOBALS_NAME ); + +/* Use Crv and Map4 to draw the curve. */ + Crv( this, d, x, y, 0, NULL, NULL, method, class, status ); + +/* End the current poly line. */ + Opoly( this, status ); + +/* Tidy up the static data used by Map4. */ + Map4( 0, NULL, NULL, NULL, method, class, status GLOBALS_NAME ); + +/* If no part of the curve could be drawn, set the number of breaks and the + length of the drawn curve to zero. */ + if( Crv_out ) { + Crv_nbrk = 0; + Crv_len = 0.0F; + +/* Otherwise, add an extra break to the returned structure at the position of + the last point to be plotted. */ + } else { + Crv_nbrk++; + if( Crv_nbrk > AST__PLOT_CRV_MXBRK ){ + astError( AST__CVBRK, "%s(%s): Number of breaks in curve " + "exceeds %d.", status, method, class, AST__PLOT_CRV_MXBRK ); + } else { + *(Crv_xbrk++) = (float) Crv_xl; + *(Crv_ybrk++) = (float) Crv_yl; + *(Crv_vxbrk++) = (float) -Crv_vxl; + *(Crv_vybrk++) = (float) -Crv_vyl; + } + } + +/* Store extra information about the curve in the returned structure, and + purge any zero length sections. */ + Curve_data.length = Crv_len; + Curve_data.out = Crv_out; + Curve_data.nbrk = Crv_nbrk; + PurgeCdata( &Curve_data, status ); + +/* Annul the Mapping. */ + Map4_map = astAnnul( Map4_map ); + +/* Ensure all lines are flushed to the graphics system. */ + Fpoly( this, method, class, status ); + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, AST__CURVE_ID, 0, GRF__LINE, method, class ); + } + +/* Return. */ + return; + +} + +static int GetLabelUnits( AstPlot *this, int axis, int *status ) { +/* +* Name: +* GetLabelUnits + +* Purpose: +* Return the value of the LabelUnits attribute for a Plot axis. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int GetLabelUnits( AstPlot *this, int axis, int *status ) + +* Class Membership: +* Plot method. + +* Description: +* This function returns the value of the LabelUnits attribute for a +* Plot axis, supplying a suitable default if not set. + +* Parameters: +* this +* The Plot. +* axis +* The axis index (zero based). +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The attribute value. + +*/ + +/* Local Variables: */ + AstFrame *fr; /* The current Frame in the Plot */ + AstFrame *primframe; /* The primary Frame holding the requested axis */ + AstSystemType system; /* The SkyFrame System attribute */ + int primaxis; /* Index of requested axis in the primary frame */ + int ret; /* The returned value */ + +/* Initialise. */ + ret = 0; + +/* Check global status. */ + if( !astOK ) return ret; + +/* If a value has been set, return it. */ + ret = this->labelunits[ axis ]; + +/* If no value has been set, find a default. */ + if( ret == -1 ) { + +/* Assume "no" for any SkyAxis axes within the current frame of the Plot, + and "yes" for other axes. Get a pointer to the current Frame of the + Plot. */ + fr = astGetFrame( this, AST__CURRENT ); + +/* The current Frame may be a CmpFrame. So find the primary Frame containing + the requested axis. The primary Frame is guaranteed not to be a CmpFrame. */ + astPrimaryFrame( fr, axis, &primframe, &primaxis ); + +/* If the primary Frame is a SkyFrame representing ICRS, equatorial, ecliptic, + galactic or supergalactic coords, use a default of "no" for LabelUnits. + Otherwise use a default of "yes". */ + ret = 1; + if( IsASkyFrame( (AstObject *) primframe, status ) ) { + system = astGetSystem( primframe ); + if( system == AST__ICRS || + system == AST__FK4 || + system == AST__FK4_NO_E || + system == AST__FK5 || + system == AST__GAPPT || + system == AST__ECLIPTIC || + system == AST__GALACTIC || + system == AST__SUPERGALACTIC ) ret = 0; + } + +/* Annul the frame pointers. */ + primframe = astAnnul( primframe ); + fr = astAnnul( fr ); + } + +/* Return the answer. */ + return ret; +} + +static void GBBuf( AstPlot *this, const char *method, + const char *class, int *status ) { +/* +* +* Name: +* GBBuf + +* Purpose: +* Call the GBBuf Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void GBBuf( AstPlot *this, const char *method, +* const char *class, int *status ) { + +* Class Membership: +* Plot private function. + +* Description: +* This function calls the GBBuf grf function to begin a new graphics +* context, either calling the version registered using astGrfSet, or +* the version in the linked grf module. The linked version is used +* if the Grf attribute is zero, or if no function has been registered +* for GBBuf using astGrfSet. + +* Parameters: +* this +* The Plot. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + int grf_status; /* Status retruned from Grf function */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Since we are about to call an external function which may not be + thread safe, prevent any other thread from executing the following code + until the current thread has finished executing it. */ + LOCK_MUTEX2; + +/* If the Grf attribute is set to a non-zero value, use the Grf function + registered using astGrfSet (so long as a function has been supplied). + This called via a wrapper which adapts the interface to suit the + language in which the function is written. */ + if( astGetGrf( this ) && this->grffun[ AST__GBBUF ] ) { + grf_status = ( *( this->GBBuf ) )( this, status ); + +/* Otherwise, use the function in the external Grf module, selected at + link-time using ast_link options.*/ + } else { + grf_status = astGBBuf(); + } + +/* Allow the next thread to proceed. */ + UNLOCK_MUTEX2; + +/* Report an error if anything went wrong. */ + if( !grf_status ) { + astError( AST__GRFER, "%s(%s): Graphics error in astGBBuf. ", status, method, + class ); + } + +} + +static void GEBuf( AstPlot *this, const char *method, + const char *class, int *status ) { +/* +* +* Name: +* GEBuf + +* Purpose: +* Call the GEBuf Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void GEBuf( AstPlot *this, const char *method, +* const char *class, int *status ) { + +* Class Membership: +* Plot private function. + +* Description: +* This function calls the GEBuf grf function to end the current graphics +* context, either calling the version registered using astGrfSet, or +* the version in the linked grf module. The linked version is used +* if the Grf attribute is zero, or if no function has been registered +* for GEBuf using astGrfSet. + +* Parameters: +* this +* The Plot. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + int grf_status; /* Status retruned from Grf function */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Since we are about to call an external function which may not be + thread safe, prevent any other thread from executing the following code + until the current thread has finished executing it. */ + LOCK_MUTEX2; + +/* If the Grf attribute is set to a non-zero value, use the Grf function + registered using astGrfSet (so long as a function has been supplied). + This called via a wrapper which adapts the interface to suit the + language in which the function is written. */ + if( astGetGrf( this ) && this->grffun[ AST__GEBUF ] ) { + grf_status = ( *( this->GEBuf ) )( this, status ); + +/* Otherwise, use the function in the external Grf module, selected at + link-time using ast_link options.*/ + } else { + grf_status = astGEBuf(); + } + +/* Allow the next thread to proceed. */ + UNLOCK_MUTEX2; + +/* Report an error if anything went wrong. */ + if( !grf_status ) { + astError( AST__GRFER, "%s(%s): Graphics error in astGEBuf. ", status, method, + class ); + } + +} + +static void GFlush( AstPlot *this, const char *method, + const char *class, int *status ) { +/* +* +* Name: +* GFlush + +* Purpose: +* Call the Gflush Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void GFlush( AstPlot *this, const char *method, +* const char *class, int *status ) { + +* Class Membership: +* Plot private function. + +* Description: +* This function calls the Gflush grf function to flush graphics, either +* calling the version registered using astGrfSet, or the version in the +* linked grf module. The linked version is used if the Grf attribute +* is zero, or if no function has been registered for Gflush using +* astGrfSet. + +* Parameters: +* this +* The Plot. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + int grf_status; /* Status retruned from Grf function */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Since we are about to call an external function which may not be + thread safe, prevent any other thread from executing the following code + until the current thread has finished executing it. */ + LOCK_MUTEX2; + +/* If the Grf attribute is set to a non-zero value, use the Grf function + registered using astGrfSet (so long as a function has been supplied). + This called via a wrapper which adapts the interface to suit the + language in which the function is written. */ + if( astGetGrf( this ) && this->grffun[ AST__GFLUSH ] ) { + grf_status = ( *( this->GFlush ) )( this, status ); + +/* Otherwise, use the function in the external Grf module, selected at + link-time using ast_link options.*/ + } else { + grf_status = astGFlush(); + } + +/* Allow the next thread to proceed. */ + UNLOCK_MUTEX2; + +/* Report an error if anything went wrong. */ + if( !grf_status ) { + astError( AST__GRFER, "%s(%s): Graphics error in astGFlush. ", status, method, + class ); + } + +} + +static void GLine( AstPlot *this, int n, const float *x, + const float *y, const char *method, + const char *class, int *status ) { +/* +* +* Name: +* GLine + +* Purpose: +* Call the Gline Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void GLine( AstPlot *this, int n, const float *x, +* const float *y, const char *method, +* const char *class, int *status ) { + +* Class Membership: +* Plot private function. + +* Description: +* This function calls the Gline grf function to draw a polyline, either +* calling the version registered using astGrfSet, or the version in the +* linked grf module. The linked version is used if the Grf attribute +* is zero, or if no function has been registered for Gline using +* astGrfSet. + +* Parameters: +* this +* The Plot. +* n +* The number of positions to be joined together. +* x +* A pointer to an array holding the "n" x values. +* y +* A pointer to an array holding the "n" y values. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + int i; /* Loop count */ + int grf_status; /* Status retruned from Grf function */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Since we are about to call an external function which may not be + thread safe, prevent any other thread from executing the following code + until the current thread has finished executing it. */ + LOCK_MUTEX2; + +/* Do not draw anything if we are using "invisible ink". */ + if( astGetInvisible( this ) ) { + grf_status = 1; + +/* If the Grf attribute is set to a non-zero value, use the Grf function + registered using astGrfSet (so long as a function has been supplied). + This is called via a wrapper which adapts the interface to suit the + language in which the function is written. */ + } else if( astGetGrf( this ) && this->grffun[ AST__GLINE ] ) { + grf_status = ( *( this->GLine ) )( this, n, x, y, status ); + +/* Otherwise, use the function in the external Grf module, selected at + link-time using ast_link options.*/ + } else { + grf_status = astGLine( n, x, y ); + } + +/* Allow the next thread to proceed. */ + UNLOCK_MUTEX2; + +/* Report an error if anything went wrong. */ + if( !grf_status ) { + astError( AST__GRFER, "%s(%s): Graphics error in astGLine. ", status, method, + class ); + +/* Otherwise, update the box containing all drawn graphics primitives. */ + } else if( !Boxp_freeze ){ + for( i = 0; i < n; i++ ) { + Boxp_lbnd[ 0 ] = astMIN( x[ i ], Boxp_lbnd[ 0 ] ); + Boxp_ubnd[ 0 ] = astMAX( x[ i ], Boxp_ubnd[ 0 ] ); + Boxp_lbnd[ 1 ] = astMIN( y[ i ], Boxp_lbnd[ 1 ] ); + Boxp_ubnd[ 1 ] = astMAX( y[ i ], Boxp_ubnd[ 1 ] ); + } + } + +} + +static void GMark( AstPlot *this, int n, const float *x, + const float *y, int type, const char *method, + const char *class, int *status ) { +/* +* +* Name: +* GMark + +* Purpose: +* Call the GMark Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void GMark( AstPlot *this, int n, const float *x, +* const float *y, int type, const char *method, +* const char *class, int *status ) { + +* Class Membership: +* Plot private function. + +* Description: +* This function calls the GMark grf function to draw markers, either +* calling the version registered using astGrfSet, or the version in the +* linked grf module. The linked version is used if the Grf attribute +* is zero, or if no function has been registered for GMark using +* astGrfSet. + +* Parameters: +* this +* The Plot. +* n +* The number of positions to be joined together. +* x +* A pointer to an array holding the "n" x values. +* y +* A pointer to an array holding the "n" y values. +* type +* An integer which can be used to indicate the type of marker symbol +* required. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + int i; /* Loop count */ + int grf_status; /* Status retruned from Grf function */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Since we are about to call an external function which may not be + thread safe, prevent any other thread from executing the following code + until the current thread has finished executing it. */ + LOCK_MUTEX2; + +/* Do not draw anything if we are using "invisible ink". */ + if( astGetInvisible( this ) ) { + grf_status = 1; + +/* If the Grf attribute is set to a non-zero value, use the Grf function + registered using astGrfSet (so long as a function has been supplied). + This is called via a wrapper which adapts the interface to suit the + language in which the function is written. */ + } else if( astGetGrf( this ) && this->grffun[ AST__GMARK ] ) { + grf_status = ( *( this->GMark ) )( this, n, x, y, type, status ); + +/* Otherwise, use the function in the external Grf module, selected at + link-time using ast_link options.*/ + } else { + grf_status = astGMark( n, x, y, type ); + } + +/* Allow the next thread to proceed. */ + UNLOCK_MUTEX2; + +/* Report an error if anything went wrong. */ + if( !grf_status ) { + astError( AST__GRFER, "%s(%s): Graphics error in astGMark. ", status, method, + class ); + +/* Otherwise, update the box containing all drawn graphics primitives. */ + } else if( !Boxp_freeze ){ + for( i = 0; i < n; i++ ) { + Boxp_lbnd[ 0 ] = astMIN( x[ i ], Boxp_lbnd[ 0 ] ); + Boxp_ubnd[ 0 ] = astMAX( x[ i ], Boxp_ubnd[ 0 ] ); + Boxp_lbnd[ 1 ] = astMIN( y[ i ], Boxp_lbnd[ 1 ] ); + Boxp_ubnd[ 1 ] = astMAX( y[ i ], Boxp_ubnd[ 1 ] ); + } + } + +} + +static void GQch( AstPlot *this, float *chv, float *chh, const char *method, + const char *class, int *status ) { +/* +* +* Name: +* GQch + +* Purpose: +* Call the GQch Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void GQch( AstPlot *this, float *chv, float *chh, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* This function calls the GQch grf function, either calling the +* version registered using astGrfSet, or the version in the linked grf +* module. The linked version is used if the Grf attribute is zero, or if +* no function has been registered for GQch using astGrfSet. + +* Parameters: +* this +* The Plot. +* chv +* A pointer to the double which is to receive the height of +* characters drawn with a vertical baseline . This will be an +* increment in the X axis. +* chh +* A pointer to the double which is to receive the height of +* characters drawn with a horizontal baseline. This will be an +* increment in the Y axis. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + int grf_status; /* Status retruned from Grf function */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* if we already have the required values, return them. */ + if( Grf_chh != AST__BAD && Grf_chv != AST__BAD ) { + *chh = Grf_chh; + *chv = Grf_chv; + return; + } + +/* Since we are about to call an external function which may not be + thread safe, prevent any other thread from executing the following code + until the current thread has finished executing it. */ + LOCK_MUTEX2; + +/* If the Grf attribute is set to a non-zero value, use the Grf function + registered using astGrfSet (so long as a function has been supplied). + This is called via a wrapper which adapts the interface to suit the + language in which the function is written. */ + if( astGetGrf( this ) && this->grffun[ AST__GQCH ] ) { + grf_status = ( *( this->GQch ) )( this, chv, chh, status ); + +/* Otherwise, use the function in the external Grf module, selected at + link-time using ast_link options.*/ + } else { + grf_status = astGQch( chv, chh ); + } + +/* Allow the next thread to proceed. */ + UNLOCK_MUTEX2; + +/* Check neither value is zero. */ + if( grf_status && ( *chh == 0.0 || *chv == 0.0 ) ) { + astError( AST__GRFER, "astGQch: Returned text heights are %g and %g " + "but zero is illegal!", status, *chv, *chh ); + grf_status = 0; + } + +/* Report an error if anything went wrong, and return safe values. */ + if( !grf_status ) { + astError( AST__GRFER, "%s(%s): Graphics error in astGQch. ", status, method, + class ); + *chh = 1.0; + *chv = 1.0; + } + +/* Store them for future use. */ + Grf_chh = *chh; + Grf_chv = *chv; +} + +static void GText( AstPlot *this, const char *text, float x, float y, + const char *just, float upx, float upy, + const char *method, const char *class, int *status ) { +/* +* +* Name: +* GText + +* Purpose: +* Call the GText Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void GText( AstPlot *this, const char *text, float x, float y, +* const char *just, float upx, float upy, +* const char *method, const char *class, int *status ) { + +* Class Membership: +* Plot private function. + +* Description: +* This function calls the GText grf function to draw a text string, either +* calling the version registered using astGrfSet, or the version in the +* linked grf module. The linked version is used if the Grf attribute +* is zero, or if no function has been registered for GText using +* astGrfSet. + +* Parameters: +* this +* The Plot. +* text +* Pointer to a null-terminated character string to be displayed. +* x +* The reference x coordinate. +* y +* The reference y coordinate. +* just +* A character string which specifies the location within the +* text string which is to be placed at the reference position +* given by x and y. The first character may be 'T' for "top", +* 'C' for "centre", or 'B' for "bottom", and specifies the +* vertical location of the reference position. Note, "bottom" +* corresponds to the base-line of normal text. Some characters +* (eg "y", "g", "p", etc) descend below the base-line. The second +* character may be 'L' for "left", 'C' for "centre", or 'R' +* for "right", and specifies the horizontal location of the +* reference position. If the string has less than 2 characters +* then 'C' is used for the missing characters. +* upx +* The x component of the up-vector for the text, in graphics world +* coordinates. If necessary the supplied value should be negated +* to ensure that positive values always refer to displacements from +* left to right on the screen. +* upy +* The y component of the up-vector for the text, in graphics world +* coordinates. If necessary the supplied value should be negated +* to ensure that positive values always refer to displacements from +* bottom to top on the screen. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + int grf_status; /* Status retruned from Grf function */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Since we are about to call an external function which may not be + thread safe, prevent any other thread from executing the following code + until the current thread has finished executing it. */ + LOCK_MUTEX2; + +/* Do not draw anything if we are using "invisible ink". */ + if( astGetInvisible( this ) ) { + grf_status = 1; + +/* If the Grf attribute is set to a non-zero value, use the Grf function + registered using astGrfSet (so long as a function has been supplied). + This is called via a wrapper which adapts the interface to suit the + language in which the function is written. */ + } else if( astGetGrf( this ) && this->grffun[ AST__GTEXT ] ) { + grf_status = ( *( this->GText ) )( this, text, x, y, just, upx, upy, status ); + +/* Otherwise, use the function in the external Grf module, selected at + link-time using ast_link options.*/ + } else { + grf_status = astGText( text, x, y, just, upx, upy ); + } + +/* Allow the next thread to proceed. */ + UNLOCK_MUTEX2; + +/* Report an error if anything went wrong. */ + if( !grf_status ) { + astError( AST__GRFER, "%s(%s): Graphics error in astGText. ", status, method, + class ); + } + +} + +static void GTxExt( AstPlot *this, const char *text, float x, float y, + const char *just, float upx, float upy, float *xbn, + float *ybn, const char *method, const char *class, int *status ) { +/* +* +* Name: +* GTxExt + +* Purpose: +* Call the GTxExt Grf function. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void GTxExt( AstPlot *this, const char *text, float x, float y, +* const char *just, float upx, float upy, float *xbn, +* float *ybn, const char *method, const char *class, int *status ) + +* Class Membership: +* Plot private function. + +* Description: +* This function calls the GTxExt grf function to find the extent +* of a text string, either calling the version registered using +* astGrfSet, or the version in the linked grf module. The linked +* version is used if the Grf attribute is zero, or if no function +* has been registered for GTxExt using astGrfSet. + +* Parameters: +* this +* The Plot. +* text +* Pointer to a null-terminated character string to be displayed. +* x +* The reference x coordinate. +* y +* The reference y coordinate. +* just +* A character string which specifies the location within the +* text string which is to be placed at the reference position +* given by x and y. The first character may be 'T' for "top", +* 'C' for "centre", or 'B' for "bottom", and specifies the +* vertical location of the reference position. Note, "bottom" +* corresponds to the base-line of normal text. Some characters +* (eg "y", "g", "p", etc) descend below the base-line. The second +* character may be 'L' for "left", 'C' for "centre", or 'R' +* for "right", and specifies the horizontal location of the +* reference position. If the string has less than 2 characters +* then 'C' is used for the missing characters. +* upx +* The x component of the up-vector for the text, in graphics world +* coordinates. If necessary the supplied value should be negated +* to ensure that positive values always refer to displacements from +* left to right on the screen. +* upy +* The y component of the up-vector for the text, in graphics world +* coordinates. If necessary the supplied value should be negated +* to ensure that positive values always refer to displacements from +* bottom to top on the screen. +* xbn +* An array of 4 elements in which to return the x coordinate of +* each corner of the bounding box. +* ybn +* An array of 4 elements in which to return the y coordinate of +* each corner of the bounding box. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Notes: +* - The corners are returned in no particular order. + +*/ + +/* Local Variables: */ + int grf_status; /* Status retruned from Grf function */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Since we are about to call an external function which may not be + thread safe, prevent any other thread from executing the following code + until the current thread has finished executing it. */ + LOCK_MUTEX2; + +/* If the Grf attribute is set to a non-zero value, use the Grf function + registered using astGrfSet (so long as a function has been supplied). + This is called via a wrapper which adapts the interface to suit the + language in which the function is written. */ + if( astGetGrf( this ) && this->grffun[ AST__GTXEXT ] ) { + grf_status = ( *( this->GTxExt ) )( this, text, x, y, just, upx, upy, + xbn, ybn, status ); + +/* Otherwise, use the function in the external Grf module, selected at + link-time using ast_link options.*/ + } else { + grf_status = astGTxExt( text, x, y, just, upx, upy, xbn, ybn ); + } + +/* Allow the next thread to proceed. */ + UNLOCK_MUTEX2; + +/* Report an error if anything went wrong. */ + if( !grf_status ) { + astError( AST__GRFER, "%s(%s): Graphics error in astGTxExt. ", status, method, + class ); + } +} + +static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { +/* +* Name: +* GetAttrib + +* Purpose: +* Get the value of a specified attribute for a Plot. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* const char *GetAttrib( AstObject *this, const char *attrib, int *status ) + +* Class Membership: +* Plot member function (over-rides the protected astGetAttrib +* method inherited from the FrameSet class). + +* Description: +* This function returns a pointer to the value of a specified +* attribute for a Plot, formatted as a character string. +* +* The value returned is the value which would actually be used if +* astGrid was called with the current set of attribute values. This +* may not always be the same as the value set by the user. For +* instance, if Labelling is set to "exterior" by the user, it may not +* be possible to produce exterior labels, in which case interior labels +* will be produced. If this function is used to get the value of +* Labelling in this situation, then the value actually used (i.e. +* interior) will be returned instead of the requested value (i.e. +* exterior). +* +* Some attributes have dynamic defaults, (i.e. the behaviour if not +* set depends on the values of other attributes). If the value for +* such an attribute is enquired using this function, then the dynamic +* default value actually used will be returned if no value has been +* set explicitly for the attribute. + +* Parameters: +* this +* Pointer to the Plot. +* attrib +* Pointer to a null terminated string containing the name of +* the attribute whose value is required. This name should be in +* lower case, with all white space removed. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* - Pointer to a null terminated string containing the attribute +* value. + +* Notes: +* - The returned string pointer may point at memory allocated +* within the Plot, or at static memory. The contents of the +* string may be over-written or the pointer may become invalid +* following a further invocation of the same function or any +* modification of the Plot. A copy of the string should +* therefore be made if necessary. +* - A NULL pointer will be returned if this function is invoked +* with the global error status set, or if it should fail for any +* reason. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstPlot *this; /* Pointer to the Plot structure */ + const char *result; /* Pointer value to return */ + char label[21]; /* Graphics item label */ + double dval; /* Double attribute value */ + int axis; /* Axis number */ + int ival; /* Int attribute value */ + int len; /* Length of attrib string */ + int nax; /* Number of base Frame axes */ + int nc; /* No. characters read by astSscanf */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this_object); + +/* Obtain a pointer to the Plot structure. */ + this = (AstPlot *) this_object; + +/* Obtain the length of the attrib string. */ + len = strlen( attrib ); + +/* Get the number of base Frame axis (2 for a Plot, 3 for a Plot3D). */ + nax = astGetNin( this ); + +/* Indicate that the current bound box should not be changed during the + execution of this function (this may happen if a grid is drawn to get + the default value for an attribute such as Labelling). */ + Boxp_freeze = 1; + +/* Compare "attrib" with each recognised attribute name in turn, + obtaining the value of the required attribute. If necessary, write + the value into "getattrib_buff" as a null terminated string in an appropriate + format. Set "result" to point at the result string. */ + +/* Tol. */ +/* ---- */ + if ( !strcmp( attrib, "tol" ) ) { + dval = astGetTol( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* Grid. */ +/* ----- */ + } else if ( !strcmp( attrib, "grid" ) ) { + ival = GetUsedGrid( this, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* TickAll. */ +/* -------- */ + } else if ( !strcmp( attrib, "tickall" ) ) { + ival = astGetTickAll( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* ForceExterior. */ +/* -------------- */ + } else if ( !strcmp( attrib, "forceexterior" ) ) { + ival = astGetForceExterior( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Invisible. */ +/* ---------- */ + } else if ( !strcmp( attrib, "invisible" ) ) { + ival = astGetInvisible( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Border. */ +/* ------- */ + } else if ( !strcmp( attrib, "border" ) ) { + ival = GetUsedBorder( this, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* ClipOp. */ +/* ------- */ + } else if ( !strcmp( attrib, "clipop" ) ) { + ival = astGetClipOp( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Clip. */ +/* ----- */ + } else if ( !strcmp( attrib, "clip" ) ) { + ival = astGetClip( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Grf. */ +/* ---- */ + } else if ( !strcmp( attrib, "grf" ) ) { + ival = astGetGrf( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* DrawTitle. */ +/* --------- */ + } else if ( !strcmp( attrib, "drawtitle" ) ) { + ival = astGetDrawTitle( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Escape. */ +/* ------- */ + } else if ( !strcmp( attrib, "escape" ) ) { + ival = astGetEscape( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* LabelAt(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "labelat(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + dval = GetUsedLabelAt( this, axis - 1, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* Centre(axis). */ +/* ------------ */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "centre(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + dval = GetUsedCentre( this, axis - 1, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* Gap. */ +/* ---- */ + } else if ( !strcmp( attrib, "gap" ) ) { + dval = GetUsedGap( this, 0, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* Gap(axis). */ +/* ---------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "gap(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + dval = GetUsedGap( this, axis - 1, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* LogGap. */ +/* ---- */ + } else if ( !strcmp( attrib, "loggap" ) ) { + dval = GetUsedLogGap( this, 0, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* LogGap(axis). */ +/* ---------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "loggap(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + dval = GetUsedLogGap( this, axis - 1, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* NumLabGap. */ +/* -------- */ + } else if ( !strcmp( attrib, "numlabgap" ) ) { + dval = astGetNumLabGap( this, 0 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* NumLabGap(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "numlabgap(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + dval = astGetNumLabGap( this, axis - 1 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* TextLabGap. */ +/* ----------- */ + } else if ( !strcmp( attrib, "textlabgap" ) ) { + dval = astGetTextLabGap( this, 0 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* TextLabGap(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "textlabgap(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + dval = astGetTextLabGap( this, axis - 1 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* LabelUp. */ +/* -------- */ + } else if ( !strcmp( attrib, "labelup" ) ) { + ival = astGetLabelUp( this, 0 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* LabelUp(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "labelup(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + ival = astGetLabelUp( this, axis - 1 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* LogPlot. */ +/* -------- */ + } else if ( !strcmp( attrib, "logplot" ) ) { + ival = astGetLogPlot( this, 0 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* LogPlot(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "logplot(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + ival = astGetLogPlot( this, axis - 1 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* LogLabel. */ +/* -------- */ + } else if ( !strcmp( attrib, "loglabel" ) ) { + ival = GetUsedLogLabel( this, 0, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* LogLabel(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "loglabel(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + ival = GetUsedLogLabel( this, axis - 1, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* LogTicks. */ +/* -------- */ + } else if ( !strcmp( attrib, "logticks" ) ) { + ival = GetUsedLogTicks( this, 0, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* LogTicks(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "logticks(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + ival = GetUsedLogTicks( this, axis - 1, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* NumLab. */ +/* -------- */ + } else if ( !strcmp( attrib, "numlab" ) ) { + ival = astGetNumLab( this, 0 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* NumLab(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "numlab(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + ival = astGetNumLab( this, axis - 1 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* MinTick. */ +/* -------- */ + } else if ( !strcmp( attrib, "mintick" ) ) { + ival = GetUsedMinTick( this, 0, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* MinTick(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "mintick(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + ival = GetUsedMinTick( this, axis - 1, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* TextLab. */ +/* ---------- */ + } else if ( !strcmp( attrib, "textlab" ) ) { + ival = GetUsedTextLab( this, 0, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* TextLab(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "textlab(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + ival = GetUsedTextLab( this, axis - 1, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* DrawAxes. */ +/* ----------- */ + } else if ( !strcmp( attrib, "drawaxes" ) ) { + ival = astGetDrawAxes( this, 0 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* DrawAxes(axis). */ +/* --------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "drawaxes(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + ival = GetDrawAxes( this, axis - 1, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Abbrev. */ +/* ----------- */ + } else if ( !strcmp( attrib, "abbrev" ) ) { + ival = astGetAbbrev( this, 0 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Abbrev(axis). */ +/* --------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "abbrev(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + ival = GetAbbrev( this, axis - 1, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* LabelUnits. */ +/* ----------- */ + } else if ( !strcmp( attrib, "labelunits" ) ) { + ival = GetUsedLabelUnits( this, 0, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* LabelUnits(axis). */ +/* ----------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "labelunits(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + ival = GetUsedLabelUnits( this, axis - 1, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Style. */ +/* ------ */ + } else if ( !strcmp( attrib, "style" ) ) { + ival = GetUseStyle( this, AST__BORDER_ID, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Style(label). */ +/* ------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "style(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + ival = GetUseStyle( this, FullForm( GrfLabels, label, attrib, "astGet", astGetClass( this ), status ), status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Font. */ +/* ----- */ + } else if ( !strcmp( attrib, "font" ) ) { + ival = GetUseFont( this, AST__TEXTLABS_ID, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Font(label). */ +/* ------------ */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "font(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + ival = GetUseFont( this, FullForm( GrfLabels, label, attrib, "astGet", astGetClass( this ), status ), status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Colour. */ +/* ------- */ + } else if ( !strcmp( attrib, "colour" ) ) { + ival = GetUseColour( this, AST__TEXTLABS_ID, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Colour(label). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "colour(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + ival = GetUseColour( this, FullForm( GrfLabels, label, attrib, "astGet", astGetClass( this ), status ), status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Color. */ +/* ------ */ + } else if ( !strcmp( attrib, "color" ) ) { + ival = GetUseColour( this, AST__TEXTLABS_ID, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Color(label). */ +/* ------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "color(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + ival = GetUseColour( this, FullForm( GrfLabels, label, attrib, "astGet", astGetClass( this ), status ), status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* Width. */ +/* ------ */ + } else if ( !strcmp( attrib, "width" ) ) { + dval = GetUseWidth( this, AST__BORDER_ID, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + + +/* Width(label). */ +/* ------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "width(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + dval = GetUseWidth( this, FullForm( GrfLabels, label, attrib, "astGet", astGetClass( this ), status ), status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* Size. */ +/* ----- */ + } else if ( !strcmp( attrib, "size" ) ) { + dval = GetUseSize( this, AST__TEXTLABS_ID, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* Size(label). */ +/* ------------ */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "size(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + dval = GetUseSize( this, FullForm( GrfLabels, label, attrib, "astGet", astGetClass( this ), status ), status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* TitleGap. */ +/* --------- */ + } else if ( !strcmp( attrib, "titlegap" ) ) { + dval = astGetTitleGap( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* MajTickLen. */ +/* ----------- */ + } else if ( !strcmp( attrib, "majticklen" ) ) { + dval = GetUsedMajTickLen( this, 0, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* MajTickLen(axis). */ +/* ----------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "majticklen(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + dval = GetUsedMajTickLen( this, axis - 1, status ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* MinTickLen. */ +/* ----------- */ + } else if ( !strcmp( attrib, "minticklen" ) ) { + dval = astGetMinTickLen( this, 0 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* MinTickLen(axis). */ +/* ----------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "minticklen(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + dval = astGetMinTickLen( this, axis - 1 ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); + result = getattrib_buff; + } + +/* Labelling. */ +/* ---------- */ + } else if ( !strcmp( attrib, "labelling" ) ) { + ival = GetUsedLabelling( this, status ); + if ( astOK ) { + result = ival ? xlbling[1] : xlbling[0]; + } + +/* Edge(axis). */ +/* ----------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "edge(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + ival = GetUsedEdge( this, axis - 1, status ); + if ( astOK ) { + if( ival == LEFT ){ + result = "left"; + } else if( ival == RIGHT ){ + result = "right"; + } else if( ival == TOP ){ + result = "top"; + } else if( ival == BOTTOM ){ + result = "bottom"; + } else { + result = "<bad>"; + } + } + +/* If the attribute name was not recognised, pass it on to the parent + method for further interpretation. */ + } else { + result = (*parent_getattrib)( this_object, attrib, status ); + } + +/* Unfreeze the bound box so that it may be updated by subsequent + plotting functions. */ + Boxp_freeze = 0; + +/* Return the result. */ + return result; +} + +static AstPointSet *GetDrawnTicks( AstPlot *this, int axis, int major, int *status ){ +/* +*+ +* Name: +* astGetDrawnTicks + +* Purpose: +* Return information about the ticks last drawn by astGrid. + +* Type: +* Protected virtual function. + +* Synopsis: +* #include "plot.h" +* AstPointSet *GetDrawnTicks( AstPlot *this, int axis, int major ) + +* Class Membership: +* Plot method. + +* Description: +* This function returns a PointSet holding information about the +* tick marks (either major and minor) that were drawn by the previous +* invocation of astGrid. A NULL pointer is returned if astGrid has +* not yet been invoked. + +* Parameters: +* this +* Pointer to a Plot. +* axis +* The zero-based axis of the axis for which tick mark information +* is required. +* major +* Supply a non-zero value if information about the major tick +* marks is to be returned, and zero if information about the minor +* tick marks is to be returned. + +* Returned Value: +* A pointSet with one point for every tick of the requested type drawn +* by astGrid for the specified axis. Each point has 2 coordinate values, +* being the graphics coordinates at the start of the tick mark. The +* returned PointSet pointer should be annulled when no longer needed. + +*- +*/ + +/* Local Variables: */ + AstPointSet *result = NULL; + double *ptr[ 3 ]; + int n; + +/* Check the global status. */ + if( !astOK ) return result; + +/* Report an error if the supplied axis value is incorrect. */ + if( axis < 0 || axis > 1 ) { + astError( AST__INTER, "astGetDrawnTicks(Plot): Supplied \"axis\" " + "value is %d - should 0 or 1 (internal AST programming " + "error).", status, axis ); + n = 0; + +/* If OK, get the number of stored tick marks. */ + } else { + n = major ? this->majtickcount[ axis ] : this->mintickcount[ axis ]; + } + +/* Check that information is available. */ + if( n > 0 && astOK ) { + +/* Create a PointSet with the required size. */ + result = astPointSet( n, 2, "", status ); + +/* Store pointers to the arrays within the Plot that hold the required + tick marks positions and types. */ + ptr[ 0 ] = major ? this->majtickgx[ axis ] : this->mintickgx[ axis ]; + ptr[ 1 ] = major ? this->majtickgy[ axis ] : this->mintickgy[ axis ]; + astSetPoints( result, ptr ); + } + +/* Return the PointSet. */ + return result; +} + +static double GetTicks( AstPlot *this, int axis, double *cen, double **ticks, + int *nmajor, double **minticks, int *nminor, + int format_set, int *inval, double *refval, + GetTicksStatics **pstatics, const char *method, + const char *class, int *status ){ +/* +* Name: +* GetTicks + +* Purpose: +* Obtain a list of logarithmically or linearly spaced tick mark values for +* a single axis in a 2-D physical coordinate Frame. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* double GetTicks( AstPlot *this, int axis, double *cen, double **ticks, +* int *nmajor, double **minticks, int *nminor, +* int format_set, int *inval, double *refval, +* GetTicksStatics **pstatics, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* For linearly spaced major ticks the "gap" returned by this function +* is the constant difference between adjacent major tick marks. For +* logarithmically spaced major ticks the "gap" returned by this +* function is the constant ratio between adjacent major tick marks. +* +* If a gap size has been specified using attribute Gap (or LogGap for +* logarithmic ticks) supplied, the specified value is returned, and used +* to determine the tick values. If no gap size is supplied, a default +* gap size is used and returned. +* +* All this is over-ridden if the astSetTickValues method has been +* called to store explicit tick mark values in the Plot structure. +* In this case, the values supplied using astSetTickValues are +* returned. + +* Parameters: +* this +* The Plot. Supplying a NULL pointer will cause statics resources +* to be released. +* axis +* The zero-based index of the axis to use. +* cen +* Pointer to the supplied axis value at which to put a single +* central tick. Other ticks will be placed evenly on either side +* of this tick. If AST__BAD is provided, a value will be used +* which would put a tick at an axis value of one. The used value +* is returned. +* ticks +* Pointer to a place at which to return a pointer to the memory in +* which are stored the major tick values to be used. This pointer +* should be freed using astFree when no longer needed. The number of +* values in the array is given by the value returned by parameter +* "nmajor". +* nmajor +* A pointer to a location at which to return the number of major +* ticks. +* minticks +* Pointer to a place at which to return a pointer to the memory in +* which are stored the minor tick values to be used. This pointer +* should be freed using astFree when no longer needed. The number of +* values in the array is given by the value returned by parameter +* "nminor". The minor tick marks values returned in this array are +* the ones stored in the Plot via a call to the astSetTickValues +* function. If this function has not been called, then a NULL +* pointer is returned, and the "nminor" value is returned holding the +* number of divisions between major ticks. +* nminor +* A pointer to a location at which to return either the number of +* division into which each gap should be divided when drawing minor +* tick marks (if "*minticks" is returned holding NULL), or the +* total number of minor tick values stored in "*minticks" (if +* "*minticks" is returned non-NULL). The number of divisions +* between major tick values is one more than the number of minor +* tick marks. +* format_set +* Indicates if an explicit format has been set for the axis. If +* not, "cen" is always assumed to be AST__BAD, and any specified +* Gap value is rounded to the nearest "nice" value. This has +* to be done because the algorithm for choosing a format avoiding +* unnecessary precision only works if the gap size causes 1 digit to +* change between adjacent labels. +* inval +* A pointer to a location at which to return a flag indicating if +* any invalid physical coordinates were encountered. +* refval +* A pointer to a location at which to return a value for the other +* axis which can be used when normalizing the returned tick mark +* values. +* pstatics +* Address of a pointer to a structure holding static data values +* used within this function. A NULL pointer should be supplied on +* the first invocation (dynamic memory will then be allocated to +* hold ths structure). The memory is freed when a NULL value for +* "this" is supplied. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The used gap size. + +* Notes: +* - This function allocates some static resources on its first +* invocation, which should be released when no longer needed, or when +* a different Plot is supplied, by calling this function with a NULL +* pointer for parameter "this". All other parameters are ignored. +* - This function assumes that the physical coordinate system is 2 +* dimensional, and it should not be used if this is not the case. +* - An error is reported if the region containing valid physical +* coordinates is too small to use. +* - If an error has already occurred, or if this function should fail +* for any reason, then a NULL pointer is returned in "ticks", zero +* is returned for the number of major and minor ticks marks. +*/ + +/* Local Variables: */ + GetTicksStatics *statics; /* Pointer to statics structure */ + double *tick; /* Pointer to next tick value */ + double cen0; /* Supplied value of cen */ + double dran; /* Dynamic range of axis values */ + double frac; /* Fraction of plot area holding good coords */ + double gap; /* Supplied value for Gap or LogGap */ + double log_used_gap; /* Log10( the used gap size ) */ + double maxv; /* Max axis value */ + double minv; /* Min axis value */ + double new_used_gap; /* New value for the used gap size */ + double old_used_gap; /* Old value for the used gap size */ + double test_gap; /* Trial gap size */ + double used_cen; /* Used value of cen */ + double used_gap; /* The used gap size */ + int findcen; /* Find a new centre value? */ + int gap_too_small; /* Test gap too small? */ + int gap_too_large; /* Test gap too large? */ + int i; /* Axis index */ + int ihi; /* Highest tick mark index */ + int ilo; /* Lowest tick mark index */ + int nochange; /* No. of ineffective attempts to change gap size */ + +/* Initialise the returned information. */ + *ticks = NULL; + *minticks = NULL; + *nmajor = 0; + *nminor = 0; + +/* Get a pointer to the supplied statics object. */ + statics = *pstatics; + +/* If a NULL pointer has been supplied for "this", release the resources + allocated on the first call to this function, and return. */ + if( !this ){ + if( statics ) { + if( statics->map ) statics->map = astAnnul( statics->map ); + if( statics->pset ) statics->pset = astAnnul( statics->pset ); + if( statics->frame ) statics->frame = astAnnul( statics->frame ); + *pstatics = astFree( statics ); + } + return 0.0; + } + +/* Check the global error status. */ + if ( !astOK ) return 0.0; + +/* If no statics structure was supplied, create one now and initialise it. */ + if( !statics ) { + statics = astMalloc( sizeof( GetTicksStatics ) ); + if( statics ) { + statics->pset=NULL; + *pstatics = statics; + } + } + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + maxv = 0.0; + minv = 0.0; + used_cen = 0.0; + used_gap = 0.0; + ihi = 0; + ilo = 0; + +/* If this is the first call to this function, do some initialisation. */ + if( !statics->pset ){ + +/* Get the Mapping from Base to Current Frame in the Plot. */ + statics->map = astGetMapping( this, AST__BASE, AST__CURRENT ); + +/* Get a pointer to the current Frame from the Plot. */ + statics->frame = astGetFrame( this, AST__CURRENT ); + +/* Get initial guesses at suitable gaps for each axis. A PointSet is + returned holding sorted values (non-normalized) for the physical axes. */ + statics->pset = DefGap( this, statics->defgaps, statics->ngood, &frac, &statics->bad, method, class, status ); + +/* Store the maximum and minimum number of major tick marks along each + axis. These numbers are reduced if only a small part of the plotting + area contains valid coordinates, so that the tick marks do not end up + to close together. */ + statics->maxticks = (int) ( 0.5 + MAJTICKS_MAX*sqrt( frac ) ); + statics->mintick = (int) ( 0.5 + MAJTICKS_MIN*sqrt( frac ) ); + if( statics->mintick < 3 ) statics->mintick = 3; + if( statics->maxticks < 8 ) statics->maxticks = 8; + if( statics->maxticks < statics->mintick ) statics->maxticks = statics->mintick; + +/* Get a pointer to the data in the PointSet. */ + statics->ptr = astGetPoints( statics->pset ); + +/* Find a typical value on each axis. */ + for( i = 0; i < 2 && astOK; i++ ){ + statics->typval[ i ] = Typical( statics->ngood[ i ], statics->ptr[ i ], -DBL_MAX, DBL_MAX, + statics->width + i, status ); + } + } + +/* Return the flag indicating if any regions of invalid physical coordinates + were found. */ + *inval = statics->bad; + +/* Return the typical value on the other axis. */ + *refval = statics->typval[ 1 - axis ]; + +/* See if any tick marks values have been stored in the Plot structure + using astSetTickValues. If so, copy the tick mark values to the + returned arrays and exit with a gap size determined by the first two + ticks. */ + if( this->nmajtickval[ axis ] > 0 ) { + *ticks = astStore( NULL, this->majtickval[ axis ], + this->nmajtickval[ axis ]*sizeof(double) ); + *minticks = astStore( NULL, this->mintickval[ axis ], + this->nmintickval[ axis ]*sizeof(double) ); + *nmajor = this->nmajtickval[ axis ]; + *nminor = this->nmintickval[ axis ]; + + if( *nmajor > 1 && (*ticks)[ 0 ] != AST__BAD && + (*ticks)[ 1 ] != AST__BAD ) { + used_gap = fabs( (*ticks)[ 1 ] - (*ticks)[ 0 ] ); + } else { + used_gap = AST__BAD; + } + + return used_gap; + + } + +/* See if the user has specified a gap size. The default for astGetLogTicks is + determined in DefGaps, so we can now decide whether to use attribute Gap + or LogGap to get the user-supplied gap size. Obtain the requested gap + attribute values for both physical axes. */ + if( astGetLogTicks( this, axis ) ) { + gap = astGetLogGap( this, axis ); + } else { + gap = astGetGap( this, axis ); + } + +/* Find the maximum and minimum value in the plotting area. DefGap will + have reported an error if minv*maxv is negative or zero. */ + if( astOK ) { + maxv = statics->ptr[ axis ][ statics->ngood[ axis ] - 1 ]; + minv = statics->ptr[ axis ][ 0 ]; + } + +/* First deal with logarithmically spaced ticks. */ + dran = ( minv != 0.0 ) ? maxv/minv : 0.0; + if( astGetLogTicks( this, axis ) ) { + +/* If the ratio of max and min data value is not larger than 10, report an + error. */ + dran = ( minv != 0.0 ) ? maxv/minv :0.0; + if( dran < 10.0 && dran > 0.1 ) { + astError( AST__VSMAL, "%s(%s): Cannot produce logarithmically " + "spaced major tick marks on axis %d since the dynamic " + "range of the axis is too small.", status, method, class, axis + 1 ); + } + +/* Should we find a new value for "cen"? */ + findcen = !cen || *cen == AST__BAD || !format_set; + +/* Try to find a "nice" gap size, so long as the caller has not supplied + a gap size. The default gap size obtained above is our initial guess. */ + if( gap == AST__BAD && astOK ){ + +/* Start off using the default gap found during the initialisation. */ + test_gap = statics->defgaps[ axis ]; + +/* Loop round until a gap size is found which gives an acceptable number + of tick marks. Upto 10 gap sizes are tried. */ + for( i = 0; i < 10 && astOK; i++ ){ + +/* Find a "nice" gap size close to the current test gap size. Also find + the number of minor tick marks to use with the nice gap size. Gaps for + logarithmic axes are always powers of ten. */ + log_used_gap = (int) ( log10( test_gap ) + 0.5 ); + if( log_used_gap == 0.0 ) { + log_used_gap = ( test_gap > 1.0 ) ? 1.0 : -1.0; + } + *nminor = 9; + used_gap = pow( 10.0, log_used_gap ); + +/* If no value has been supplied for *cen, choose a value which would put + a major tick mark at the value 1 (or -1), and which is mid way between + the maximum and minimum axis value. */ + if( findcen ) { + used_cen = pow( used_gap, (int) ( 0.5*log10( maxv*minv ) / + log_used_gap ) ); + if( maxv < 0 ) used_cen = -used_cen; + } else { + used_cen = *cen; + } + +/* Find the index of the highest tick which is not larger than the lowest + axis value. */ + if( log_used_gap > 0.0 ) { + ilo = floor( log10( minv/used_cen )/log_used_gap ); + } else { + ilo = ceil( log10( minv/used_cen )/log_used_gap ); + } + +/* Find the index of the lowest tick which is not less than the highest + axis value. */ + if( log_used_gap > 0.0 ) { + ihi = ceil( log10( maxv/used_cen )/log_used_gap ); + } else { + ihi = floor( log10( maxv/used_cen )/log_used_gap ); + } + +/* Find the total number of tick marks. */ + *nmajor = ihi - ilo + 1; + +/* If the number of ticks is unacceptable, try a different gap size. If the + gap was too large to produce any ticks, try using half the gap size. */ + if( *nmajor <= 0 ) { + test_gap = sqrt( test_gap ); + +/* If there were some ticks, but not enough, decrease the gap size in + proportion to the shortfall. */ + } else if( *nmajor < statics->mintick ){ + test_gap = pow( test_gap, (double)( *nmajor )/(double)( statics->mintick ) ); + +/* If there were too many ticks, increase the gap size in proportion to the + excess. */ + } else if( *nmajor > statics->maxticks ){ + test_gap = pow( test_gap, (double)( *nmajor )/(double)( statics->maxticks ) ); + +/* If the number of ticks is acceptable, break out of the loop early.*/ + } else { + break; + } + } + +/* Increase the tick coverage by one at each end to cover up the gaps. */ + ilo--; + ihi++; + *nmajor += 2; + +/* If an explicit gap size was supplied, use it. */ + } else if( astOK ) { + +/* Check it is usable. */ + if( gap == 0.0 && astOK ) { + astError( AST__ATTIN, "%s(%s): Invalid value zero given for " + "attribute LogGap(%d).", status, method, class, axis + 1 ); + + } else if( gap < 0.0 && astOK ) { + astError( AST__ATTIN, "%s(%s): Invalid negative value %f given for " + "attribute LogGap(%d).", status, method, class, gap, axis + 1 ); + +/* If necessary, take its reciprocal in order to ensure that the absolute + tick mark values get smaller or larger as required. */ + } else { + + used_gap = gap; + if( fabs( maxv ) < fabs( minv ) ) { + if( gap > 1.0 ) used_gap = 1.0/gap; + } else { + if( gap < 1.0 ) used_gap = 1.0/gap; + } + +/* Find the nearest power of 10 ( do not allow 10**0 (=1.0) to be used). */ + log_used_gap = (int) ( log10( used_gap ) + 0.5 ); + if( log_used_gap == 0.0 ) { + log_used_gap = ( gap > 1.0 ) ? 1.0 : -1.0; + } + used_gap = pow( 10.0, log_used_gap ); + +/* We always use 9 minor intervals. */ + *nminor = 9; + +/* If no value has been supplied for *cen, choose a value which would put + a major tick mark at the value 1 (or -1), and which is mid way between + the maximum and minimum axis value. */ + if( findcen ) { + used_cen = pow( used_gap, (int) ( 0.5*log10( maxv*minv ) / + log_used_gap ) ); + if( maxv < 0 ) used_cen = -used_cen; + } else { + used_cen = *cen; + } + +/* Find the index of the highest tick which is not larger than the lowest + axis value. */ + if( log_used_gap > 0.0 ) { + ilo = floor( log10( minv/used_cen )/log_used_gap ); + } else { + ilo = ceil( log10( minv/used_cen )/log_used_gap ); + } + +/* Find the index of the lowest tick which is not less than the highest + axis value. */ + if( log_used_gap > 0.0 ) { + ihi = ceil( log10( maxv/used_cen )/log_used_gap ); + } else { + ihi = floor( log10( maxv/used_cen )/log_used_gap ); + } + +/* Find the total number of tick marks. */ + *nmajor = ihi - ilo + 1; + if( *nmajor < 2 && astOK ) { + astError( AST__ATTIN, "%s(%s): Unusable value %f given for " + "attribute LogGap(%d).", status, method, class, gap, axis + 1 ); + + } + } + } + +/* Allocate memory to hold the tick values themselves. */ + *ticks = (double *) astMalloc( sizeof( double )*( *nmajor ) ); + if( astOK ) { + +/* Store them. */ + tick = *ticks; + for( i = ilo; i <= ihi; i++, tick++ ) { + *tick = used_cen*pow( used_gap, i ); + } + } + +/* Store returned centre value. */ + if( cen ) *cen = used_cen; + +/* Now deal with linearly spaced ticks */ + } else { + +/* Store the supplied value of cen. */ + cen0 = ( cen ) ? *cen : AST__BAD; + +/* If no format has been set for the axis, ensure AST__BAD is used for cen. */ + if( !format_set ) cen0 = AST__BAD; + +/* Try to find a "nice" gap size, so long as the caller has not supplied + a gap size. The default gap size obtained above is our initial guess. */ + if( gap == AST__BAD ){ + old_used_gap = AST__BAD; + +/* Start of using the default gap found during the initialisation. */ + test_gap = statics->defgaps[ axis ]; + used_gap = 0.0; + +/* Initialise flags saying the test gap is too large or too small */ + gap_too_large = 0; + gap_too_small = 0; + +/* So far, there have been no ineffective attempts to change the gap + size. */ + nochange = 0; + +/* Loop round until a gap size is found which gives an acceptable number + of tick marks. Upto 10 gap sizes are tried. */ + for( i = 0; i < 10 && astOK; i++ ){ + +/* Find a "nice" gap size close to the current test gap size. Also find + the number of minor tick marks to use with the nice gap size. */ + new_used_gap = astGap( statics->frame, axis, test_gap, nminor ); + +/* Find the number and positions of major tick marks which would result + from using this gap size. Annul the memory used to hold any previous tick + data first. Only do this if the gap being used has actually changed, + otherwise we just retain the values created from the previous run with + this gap size. */ + if( new_used_gap != used_gap ) { + nochange = 0; + old_used_gap = used_gap; + used_gap = new_used_gap; + if( *ticks ) *ticks = astFree( *ticks ); + if( cen ) *cen = cen0; + *nmajor = FindMajTicks( statics->map, statics->frame, axis, *refval, statics->width[ 1-axis ], + used_gap, cen, statics->ngood[ axis ], + statics->ptr[ axis ], ticks, status ); + +/* If the gap size has not changed do an extra pass through this loop, + but only do this a maximum of 25 times in succession. */ + } else if( nochange < 25 ) { + nochange++; + i--; + + } else if( astOK ){ + astError( AST__VSMAL, "%s(%s): Cannot produce enough major " + "tick marks on axis %d using the current axis " + "format (\"%s\").", status, method, class, axis + 1, + astGetFormat( statics->frame, axis ) ); + break; + } + +/* If the number of ticks is unacceptable, try a different gap size. If the + gap was too large to produce any ticks, try using half the gap size. */ + if( *nmajor == 0 ) { + test_gap *= 0.5; + gap_too_large = 1; + gap_too_small = 0; + +/* If there were some ticks, but not enough... */ + } else if( *nmajor < statics->mintick ){ + +/* If the previous test gap produced too many ticks, use the current gap + size. */ + if( gap_too_small ) { + break; + +/* Otherwise, decrease the gap size in proportion to the shortfall. */ + } else { + test_gap *= (double)( *nmajor )/(double)( statics->mintick ); + gap_too_large = 1; + gap_too_small = 0; + } + +/* If there were too many ticks... */ + } else if( *nmajor > statics->maxticks ){ + +/* If the previous test gap produced too few ticks, use the previous gap + size. */ + if( gap_too_large ) { + used_gap = old_used_gap; + if( *ticks ) *ticks = astFree( *ticks ); + if( cen ) *cen = cen0; + *nmajor = FindMajTicks( statics->map, statics->frame, axis, *refval, statics->width[ 1-axis ], + used_gap, cen, statics->ngood[ axis ], + statics->ptr[ axis ], ticks, status ); + break; + +/* Otherwise, increase the gap size in proportion to the excess. */ + } else { + test_gap *= (double)( *nmajor )/(double)( statics->maxticks ); + gap_too_small = 1; + gap_too_large = 0; + } + +/* If the number of ticks is acceptable, break out of the loop early.*/ + } else { + break; + } + } + +/* If an explicit gap size was supplied, use it. */ + } else { + +/* Find a likely value for the number of minor tick marks to use, and find + a nice gap close to the supplied gap (unless an explicit format has + been set). */ + if( format_set ){ + used_gap = gap; + (void) astGap( statics->frame, axis, used_gap, nminor ); + } else { + used_gap = astGap( statics->frame, axis, gap, nminor ); + } + +/* Find where the major ticks should be put. */ + if( cen ) *cen = cen0; + *nmajor = FindMajTicks( statics->map, statics->frame, axis, *refval, statics->width[ 1-axis ], + used_gap, cen, statics->ngood[ axis ], statics->ptr[ axis ], + ticks, status ); + } + } + +/* Report an error if no ticks can be found. */ + if( *nmajor == 0 && astOK ) { + astError( AST__GRFER, "%s(%s): Cannot find any usable tick mark values. ", status, method, + class ); + } + +/* If an error has occurred, annul the memory used to hold tick data, and + return zero ticks. */ + if( !astOK ) { + *ticks = (double *) astFree( (void *) *ticks ); + *nmajor = 0; + *nminor = 0; + used_gap = 0.0; + } + +/* Return. */ + return used_gap; +} + +static double GoodGrid( AstPlot *this, int *dim, AstPointSet **pset1, + AstPointSet **pset2, const char *method, + const char *class, int *status ){ +/* +* Name: +* GoodGrid + +* Purpose: +* Create a grid covering the region containing good coordinates in a +* 2-D physical coordinate Frame. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* double GoodGrid( AstPlot *this, int *dim, AstPointSet **pset1, +* AstPointSet **pset2, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function creates two PointSets, one holding a square grid of +* graphics coordinates, and the other holding the corresponding physical +* coordinates (not normalized). The grid covers just the area containing +* good physical coordinates. The points are stored row by row in the +* returned PointSets. + +* Parameters: +* this +* The Plot. +* dim +* A pointer to an integer in which to store the number of samples +* along each edge of the returned grid. +* pset1 +* A pointer to a location at which to store a pointer to the +* PointSet holding the graphics coordinates. +* pset2 +* A pointer to a location at which to store a pointer to the +* PointSet holding the physical coordinates. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The fraction of the plotting area containing good physical +* coordinates. + +* Notes: +* - This function assumes that the physical coordinate system is 2 +* dimensional, and it should not be used if this is not the case. +* - The returned PointSets should be annulled when no longer needed, +* using astAnnul. +* - An error is reported if the region containing valid physical +* coordinates is too small to use. +* - A function value of zero, and NULL pointers are returned if an error +* has already occurred, or if this function should fail for any reason. +*/ + +/* Local Variables: */ + AstFrame *frm; /* Pointer to the Current Frame in the Plot */ + AstMapping *map; /* Pointer to "graphics to physical" mapping */ + double **ptr1; /* Pointer to physical axis value data */ + double **ptr2; /* Pointer to graphics axis value data */ + double *pa; /* Pointer to next value on 1st physical axis */ + double *pb; /* Pointer to next value on 2nd physical axis */ + double *px; /* Pointer to next value on 1st graphics axis */ + double *py; /* Pointer to next value on 2nd graphics axis */ + double dx; /* Cell size along graphics X (1st) axis */ + double dy; /* Cell size along graphics Y (2nd) axis */ + double frac; /* Fraction of good physical coordinates */ + double xmax; /* High X bound of region containing good phy. coords */ + double xmin; /* Low X bound of region containing good phy. coords */ + double ymax; /* High Y bound of region containing good phy. coords */ + double ymin; /* Low Y bound of region containing good phy. coords */ + int j; /* Element offset */ + int ngood; /* Number of grid points with good physical coords */ + int size; /* Number of grid points */ + +/* Initialise the returned PointSet pointers. */ + *pset1 = NULL; + *pset2 = NULL; + +/* Check the global error status. */ + if ( !astOK ) return 0.0; + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + ptr1 = NULL; + frac = 0.0; + xmax = 0.0; + xmin = 0.0; + ymax = 0.0; + ymin = 0.0; + +/* Get the Mapping from base (graphics) to current (physical) Frame in the + supplied Plot. */ + map = astGetMapping( this, AST__BASE, AST__CURRENT ); + +/* Get a pointer to the Current Frame in the Plot. */ + frm = astGetFrame( this, AST__CURRENT ); + +/* Initialise the grid dimension. */ + *dim = 16; + +/* We need a grid which has at least 4 good points. */ + ngood = 0; + while( ngood < 4 && astOK ){ + +/* Double the grid dimension. */ + *dim *= 2; + +/* Report an error if the grid is now too big. */ + if( *dim >= 512 ){ + astError( AST__VSMAL, "%s(%s): The area of the plot containing " + "usable coordinates on both axes is too small.", status, method, + class ); + break; + } + +/* Get two PointSets, one holding a regular grid of graphics coordinates, + and the other holding the corresponding physical coordinates. The grid + covers the entire plotting area with the current grid dimension. A + pointer to the physical axis values is returned. */ + ptr2 = MakeGrid( this, frm, map, 1, *dim, this->xlo, this->xhi, this->ylo, + this->yhi, 2, pset1, pset2, 0, method, class, status ); + +/* Get the number of graphics axis values. */ + size = astGetNpoint( *pset1 ); + +/* Get a pointer to the graphics axis values. */ + ptr1 = astGetPoints( *pset1 ); + +/* Check the pointers can be used. */ + if( astOK ){ + +/* Find the bounds in graphics coordinates of the area enclosing the + good physical positions in the grid, and count the good positions. */ + ngood = 0; + + pa = ptr2[ 0 ]; + pb = ptr2[ 1 ]; + px = ptr1[ 0 ]; + py = ptr1[ 1 ]; + + xmin = DBL_MAX; + xmax = -DBL_MAX; + ymin = DBL_MAX; + ymax = -DBL_MAX; + + for( j = 0; j < size; j++ ){ + if( *pa != AST__BAD && *pb != AST__BAD ){ + if( *px < xmin ) xmin = *px; + if( *px > xmax ) xmax = *px; + if( *py < ymin ) ymin = *py; + if( *py > ymax ) ymax = *py; + ngood++; + } + px++; + py++; + pa++; + pb++; + } + } + } + +/* Store approximate fraction of the plotting area containing good + physical coordinates. */ + if( astOK ) { + frac = ( (double) ngood )/(double)( astGetNpoint( *pset1 ) ); + +/* Get the size of each grid cell. */ + dx = ptr1[0][1] - ptr1[0][0]; + dy = ptr1[1][1] - ptr1[1][0]; + +/* Extend the area containing good points by one grid cell. */ + xmax += dx; + xmin -= dx; + ymax += dy; + ymin -= dy; + +/* If the area containing good points is significantly smaller than + the supplied area, create a new grid covering just the area containing + good positions. */ + if( ( xmax - xmin ) < 0.9*( this->xhi - this->xlo ) || + ( ymax - ymin ) < 0.9*( this->yhi - this->ylo ) ){ + +/* Find a new grid dimension which results in a cell size similar to + the one used to create the grid, but covering only the region containing + good physical coordinates. */ + *dim *= astMAX( (xmax - xmin)/(this->xhi - this->xlo), + (ymax - ymin)/(this->yhi - this->ylo) ); + if( *dim < 32 ) *dim = 32; + +/* Annul the PointSet holding the current grid. */ + *pset1 = astAnnul( *pset1 ); + *pset2 = astAnnul( *pset2 ); + +/* Create the new grid covering the region containing good physical + coordinates. */ + (void) MakeGrid( this, frm, map, 1, *dim, xmin, xmax, ymin, ymax, 2, + pset1, pset2, 0, method, class, status ); + } + } + +/* Annul the Mapping from base to current Frame, and the pointer to the + Current Frame. */ + map = astAnnul( map ); + frm = astAnnul( frm ); + +/* If an error has occurred, annul the two pointsets and indicate that + there are no good points in the plotting area. */ + if( !astOK ){ + *pset1 = astAnnul( *pset1 ); + *pset2 = astAnnul( *pset2 ); + frac = 0.0; + } + +/* Return. */ + return frac; + +} + +static int GraphGrid( int dim, int disk, double xlo, double xhi, double ylo, + double yhi, double **ptr1, int *status ){ +/* +* Name: +* GraphGrid + +* Purpose: +* Fill an array with a square grid of graphics coordinates. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int GraphGrid( int dim, int disk, double xlo, double xhi, double ylo, +* double yhi, double **ptr1, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function fills the supplied array with a square grid of graphics +* coordinates covering the supplied area. The points are stored row by +* row, i.e. if the cell size for the grid is (dx,dy), the first point +* is (xmin,ymin), followed by (xmin+dx,ymin), (xmin+2*dx,ymin), up to +* (xmin+(dim-1)*dx,ymin), followed by the next row (xmin,ymin+dy), +* (xmin+dx,ymin+dy), etc. + +* Parameters: +* dim +* The number of samples along each edge of the grid. +* disk +* If non-zero, the corners of the grid are omitted, resulting in a +* grid that is more disk like than rectangular. +* xlo +* The lower bound on the first axis of the region to be covered +* by the grid. +* xhi +* The upper bound on the first axis of the region to be covered +* by the grid. +* ylo +* The lower bound on the second axis of the region to be covered +* by the grid. +* yhi +* The upper bound on the second axis of the region to be covered +* by the grid. +* ptr1 +* A pointer to an array of two pointers giving the start of the two +* arrays to receive the values for each of the two axes of the graphics +* coordinate data. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The number of points in the grid. If "disk" is zero, this will be +* the square of "dim". If "disk" is non-zero, this will be less than +* the square of "dim" to account for the lack of corner points. + +*/ + +/* Local Variables: */ + double *px; + double *py; + double cen; + double dx; + double dy2; + double dy; + double dx2; + double r2; + double y; + int i; + int j; + int ok; + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* Find the cell size. */ + dx = ( xhi - xlo )/(double)( dim - 1 ); + dy = ( yhi - ylo )/(double)( dim - 1 ); + +/* Store the mid cell index. */ + cen = 0.5*( dim - 1 ); + +/* Store the squared radius of the disk. */ + r2 = 1.9*cen*cen; + +/* Initialise pointers to the start of the two arrays to recieve the + returned graphics values for each axis. */ + px = ptr1[ 0 ]; + py = ptr1[ 1 ]; + +/* Loop round row. */ + for( j = 0; j < dim; j++ ){ + dy2 = j - cen; + dy2 *= dy2; + +/* Get the Y coordinate of the current row. */ + y = ylo + j*dy; + +/* Loop round each column in the current row. */ + for( i = 0; i < dim; i++ ){ + +/* If we are forming a disk rather than a square, check if this point is + sufficiently close to the centre to be included in the disk. */ + if( disk ) { + dx2 = i - cen; + dx2 *= dx2; + ok = ( dx2 + dy2 <= r2 ); + } else { + ok = 1; + } + +/* Store the coordinates of the current grid point. */ + if( ok ) { + *(px++) = xlo + i*dx; + *(py++) = y; + } + } + } + +/* Return the used length of the PointSet. */ + return (int)( px - ptr1[ 0 ] ); +} + +static void GrfPop( AstPlot *this, int *status ) { +/* +*++ +* Name: +c astGrfPop +f AST_GRFPOP + +* Purpose: +* Restore previously saved graphics functions used by a Plot. + +* Type: +* Public function. + +* Synopsis: +c #include "plot.h" +c void astGrfPop( AstPlot *this ) +f CALL AST_GRFPOP( THIS STATUS ) + +* Class Membership: +* Plot member function. + +* Description: +c This function restores a snapshot of the graphics functions +c stored previously by calling astGrfPush. The restored graphics +c functions become the current graphics functions used by the Plot. +* +c The astGrfPush and astGrfPop functions are intended for situations +c where it is necessary to make temporary changes to the graphics +c functions used by the Plot. The current functions should first be +c saved by calling astGrfPush. New functions should then be registered +c using astGrfSet. The required graphics should then be produced. +c Finally, astGrfPop should be called to restore the original graphics +c functions. +f The AST_GRFPUSH and AST_GRFPOP functions are intended for situations +f where it is necessary to make temporary changes to the graphics +f functions used by the Plot. The current functions should first be +f saved by calling AST_GRFPUSH. New functions should then be registered +f using AST_GRFSET. The required graphics should then be produced. +f Finally, AST_GRFPOP should be called to restore the original graphics +f functions. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +f - This routine returns without action if there are no snapshots to +c - This function returns without action if there are no snapshots to +* restore. No error is reported in this case. + +*-- +*/ + +/* Local Variables: */ + AstGrfPtrs *newframe; /* Pointer to the stack frame to restore */ + int i; /* Loop count */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Check the stack is not already empty. */ + if( this->grfnstack > 0 ) { + this->grfnstack--; + + if( astOK ) { + newframe = this->grfstack + this->grfnstack; + + for( i = 0; i < AST__NGRFFUN; i++ ) { + this->grffun[i] = (newframe->grffun)[i]; + } + this->GAttr = newframe->GAttr; + this->GBBuf = newframe->GBBuf; + this->GEBuf = newframe->GEBuf; + this->GFlush = newframe->GFlush; + this->GLine = newframe->GLine; + this->GMark = newframe->GMark; + this->GText = newframe->GText; + this->GCap = newframe->GCap; + this->GTxExt = newframe->GTxExt; + this->GScales = newframe->GScales; + this->GQch = newframe->GQch; + } + } +} + +static void GrfPush( AstPlot *this, int *status ) { +/* +*++ +* Name: +c astGrfPush +f AST_GRFPUSH + +* Purpose: +* Save the current graphics functions used by a Plot. + +* Type: +* Public function. + +* Synopsis: +c #include "plot.h" +c void astGrfPush( AstPlot *this ) +f CALL AST_GRFPUSH( THIS STATUS ) + +* Class Membership: +* Plot member function. + +* Description: +c This function takes a snapshot of the graphics functions which are +f This routine takes a snapshot of the graphics functions which are +* currently registered with the supplied Plot, and saves the snapshot +* on a first-in-last-out stack within the Plot. The snapshot can be +* restored later using function +c astGrfPop. +f AST_GRFPOP. +* +c The astGrfPush and astGrfPop functions are intended for situations +c where it is necessary to make temporary changes to the graphics +c functions used by the Plot. The current functions should first be +c saved by calling astGrfPush. New functions should then be registered +c using astGrfSet. The required graphics should then be produced. +c Finally, astGrfPop should be called to restore the original graphics +c functions. +f The AST_GRFPUSH and AST_GRFPOP functions are intended for situations +f where it is necessary to make temporary changes to the graphics +f functions used by the Plot. The current functions should first be +f saved by calling AST_GRFPUSH. New functions should then be registered +f using AST_GRFSET. The required graphics should then be produced. +f Finally, AST_GRFPOP should be called to restore the original graphics +f functions. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +f STATUS = INTEGER (Given and Returned) +f The global status. + +*-- +*/ + +/* Local Variables: */ + AstGrfPtrs *newframe; /* Pointer to the new stack frame */ + int i; /* Loop count */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Increment the number of frames on the stack. */ + this->grfnstack++; + +/* Ensure the stack is large enough to hold this many frames. */ + this->grfstack = (AstGrfPtrs *) astGrow( (void *) this->grfstack, + this->grfnstack, sizeof( AstGrfPtrs ) ); + if( astOK ) { + +/* Get a pointer to the new stack frame. */ + newframe = this->grfstack + this->grfnstack - 1; + +/* Copy the graphics function pointers from the main Plot attributes + to the new stack frame. */ + for( i = 0; i < AST__NGRFFUN; i++ ) { + (newframe->grffun)[i] = this->grffun[i]; + } + newframe->GAttr = this->GAttr; + newframe->GBBuf = this->GBBuf; + newframe->GEBuf = this->GEBuf; + newframe->GFlush = this->GFlush; + newframe->GLine = this->GLine; + newframe->GMark = this->GMark; + newframe->GText = this->GText; + newframe->GCap = this->GCap; + newframe->GTxExt = this->GTxExt; + newframe->GQch = this->GQch; + newframe->GScales = this->GScales; + } +} + +static void GrfSet( AstPlot *this, const char *name, AstGrfFun fun, int *status ){ +/* +*++ +* Name: +c astGrfSet +f AST_GRFSET + +* Purpose: +c Register a graphics function for use by a Plot. +f Register a graphics routine for use by a Plot. + +* Type: +* Public function. + +* Synopsis: +c #include "plot.h" +c void astGrfSet( AstPlot *this, const char *name, AstGrfFun fun ) +f CALL AST_GRFSET( THIS, NAME, FUN, STATUS ) + +* Class Membership: +* Plot member function. + +* Description: +c This function can be used to select the underlying graphics +c functions to be used when the supplied Plot produces graphical output. +c If this function is not called prior to producing graphical +c output, then the underlying graphics functions selected at +c link-time (using the ast_link command) will be used. To use +c alternative graphics functions, call this function before +c the graphical output is created, specifying the graphics +c functions to be used. This will register the function for future +c use, but the function will not actually be used until the Grf +c attribute is given a non-zero value. +f This routine can be used to select the underlying graphics +f routines to be used when the supplied Plot produces graphical output. +f If this routine is not called prior to producing graphical +f output, then the underlying graphics routines selected at +f link-time (using the ast_link command) will be used. To use +f alternative graphics routines, call this routine before +f the graphical output is created, specifying the graphics +f routines to be used. This will register the routine for future +f use, but the routine will not actually be used until the Grf +f attribute is given a non-zero value. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +c name +f NAME = CHARACTER * ( * ) (Given) +c A name indicating the graphics function to be replaced. +c Various graphics functions are used by the +c Plot class, and any combination of them may be supplied by calling +c this function once for each function to be replaced. If any of the +c graphics functions are not replaced in this way, the +c corresponding functions in the graphics interface selected at +c link-time (using the ast_link command) are used. The allowed +c names are: +f A name indicating the graphics routine to be replaced. +f Various graphics routines are used by the +f Plot class, and any combination of them may be supplied by calling +f this routine once for each routine to be replaced. If any of the +f graphics routines are not replaced in this way, the +f corresponding routines in the graphics interface selected at +f link-time (using the ast_link command) are used. The allowed +f function names are: +* +* - Attr - Enquire or set a graphics attribute value +* - BBuf - Start a new graphics buffering context +* - Cap - Inquire a capability +* - EBuf - End the current graphics buffering context +* - Flush - Flush all pending graphics to the output device +* - Line - Draw a polyline (i.e. a set of connected lines) +* - Mark - Draw a set of markers +* - Qch - Return the character height in world coordinates +* - Scales - Get the axis scales +* - Text - Draw a character string +* - TxExt - Get the extent of a character string +* +* The string is case insensitive. For details of the interface +* required for each, see the sections below. +c fun +f FUN = INTEGER FUNCTION (Given) +c A Pointer to the function to be used to provide the +c functionality indicated by parameter name. The interface for +c each function is described below, but the function pointer should +c be cast to a type of AstGrfFun when calling astGrfSet. +f The name of the routine to be used to provide the +f functionality indicated by parameter NAME (the name +f should also appear in a Fortran EXTERNAL statement in the +f routine which invokes AST_GRFSET). +* +c Once a function has been provided, a null pointer can be supplied +c in a subsequent call to astGrfSet to reset the function to the +c corresponding function in the graphics interface selected at +c link-time. +f Once a routine has been provided, the "null" routine AST_NULL can +f be supplied in a subsequent call to astGrfSet to reset the routine +f to the corresponding routine in the graphics interface selected at +f link-time. AST_NULL is defined in the AST_PAR include file. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Function Interfaces: +* All the functions listed below (except for "Cap") should return an +* integer value of 0 if an error occurs, and 1 otherwise. All x and y +* values refer +f to "graphics cordinates" as defined by the GRAPHBOX parameter of +f the AST_PLOT call which created the Plot. +c to "graphics cordinates" as defined by the graphbox parameter of +c the astPlot call which created the Plot. +* +c The first parameter ("grfcon") +f The first argument (GRFCON) +* for each function is an AST KeyMap pointer that can be used by the +* called function to establish the context in which it is being called. +* The contents of the KeyMap are determined by the calling +* application, which should obtain a pointer to the KeyMap using the +f AST_GETGRFCONTEXT routine, +c astGetGrfContext function, +* and then store any necessary information in the KeyMap using the +* methods of the KeyMap class. Note, the functions listed below +* should never annul or delete the supplied KeyMap pointer. + +* Attr: +* The "Attr" function returns the current value of a specified graphics +* attribute, and optionally establishes a new value. The supplied +* value is converted to an integer value if necessary before use. +* It requires the following interface: +* +c int Attr( AstObject *grfcon, int attr, double value, double *old_value, int prim ) +f INTEGER FUNCTION ATTR( GRFCON, ATT, VAL, OLDVAL, PRIM ) +* +c - grfcon - +f - GRFCON = INTEGER (Given) - +* A KeyMap containing information passed from the calling application. +c - attr - An integer value identifying the required attribute. +c The following symbolic values are defined in grf.h: +f - ATT = INTEGER (Given) - An integer identifying the required attribute. +f The following symbolic values are defined in GRF_PAR: +* GRF__STYLE (Line style), +* GRF__WIDTH (Line width), +* GRF__SIZE (Character and marker size scale factor), +* GRF__FONT (Character font), +* GRF__COLOUR (Colour index). +c - value - +f - VAL = DOUBLE PRECISION (Given) - +c A new value to store for the attribute. If this is AST__BAD +* no value is stored. +c - old_value - A pointer to a double in which to return +f - OLDVAL = DOUBLE PRECISION (Returned) - Returned holding +* the attribute value. +c If this is NULL, no value is returned. +c - prim - +f - PRIM = INTEGER (Given) - +* The sort of graphics primitive to be drawn with the new attribute. +c Identified by the following values defined in grf.h: +f Identified by the following values defined in GRF_PAR: +* GRF__LINE, +* GRF__MARK, +* GRF__TEXT. + +* BBuf: +* The "BBuf" function should start a new graphics buffering context. +* A matching call to the function "EBuf" should be used to end the +* context. The nature of the buffering is determined by the underlying +* graphics system. +* +c int BBuf( AstObject *grfcon ) +f INTEGER FUNCTION BBUF( GRFCON ) +* +c - grfcon - +f - GRFCON = INTEGER (Given) - +* A KeyMap containing information passed from the calling application. + +* Cap: +* The "Cap" function is called to determine if the grf module has a +* given capability, as indicated by the "cap" argument: +* +c int Cap( AstObject *grfcon, int cap, int value ) +f INTEGER FUNCTION CAP( GRFCON, CAP, VALUE ) +* +c - grfcon - +f - GRFCON = INTEGER (Given) - +* A KeyMap containing information passed from the calling application. +c - cap - +f - CAP = INTEGER (Given) +* The capability being inquired about. This will be one of the +c following constants defined in grf.h: +f following constants defined in GRF_PAR: +* +* GRF__SCALES: This function should return a non-zero value if the +* "Scales" function is implemented, and zero otherwise. The supplied +c "value" argument should be ignored. +f VALUE argument should be ignored. +* +* GRF__MJUST: This function should return a non-zero value if +* the "Text" and "TxExt" functions recognise "M" as a +* character in the justification string. If the first character of +* a justification string is "M", then the text should be justified +* with the given reference point at the bottom of the bounding box. +* This is different to "B" justification, which requests that the +* reference point be put on the baseline of the text, since some +* characters hang down below the baseline. If the "Text" or +* "TxExt" function cannot differentiate between "M" and "B", +* then this function should return zero, in which case "M" +* justification will never be requested by Plot. The supplied +c "value" argument should be ignored. +f VALUE argument should be ignored. +* +* GRF__ESC: This function should return a non-zero value if the +* "Text" and "TxExt" functions can recognise and interpret +* graphics escape sequences within the supplied string (see +* attribute Escape). Zero should be returned if escape sequences +* cannot be interpreted (in which case the Plot class will interpret +c them itself if needed). The supplied "value" argument should be +f them itself if needed). The supplied VALUE argument should be +* ignored only if escape sequences cannot be interpreted by "Text" and +c "TxExt". Otherwise, "value" indicates whether "Text" and "TxExt" +c should interpret escape sequences in subsequent calls. If "value" is +f "TxExt". Otherwise, VALUE indicates whether "Text" and "TxExt" +f should interpret escape sequences in subsequent calls. If VALUE is +* non-zero then escape sequences should be interpreted by "Text" and +* "TxExt". Otherwise, they should be drawn as literal text. +* +c - value - +f - VALUE = INTEGER (Given) +c The use of this parameter depends on the value of "cap" as +f The use of this parameter depends on the value of CAP as +* described above. + +* - Returned Function Value: +c The value returned by the function depends on the value of "cap" +f The value returned by the function depends on the value of CAP +* as described above. Zero should be returned if the supplied +* capability is not recognised. + +* EBuf: +* The "EBuf" function should end the current graphics buffering +* context. See the description of "BBuf" above for further details. +* It requires the following interface: +* +c int EBuf( AstObject *grfcon ) +f INTEGER FUNCTION EBUF( GRFCON ) +* +c - grfcon - +f - GRFCON = INTEGER (Given) - +* A KeyMap containing information passed from the calling application. + +* Flush: +* The "Flush" function ensures that the display device is up-to-date, +* by flushing any pending graphics to the output device. It +* requires the following interface: +* +c int Flush( AstObject *grfcon ) +f INTEGER FUNCTION FLUSH( GRFCON ) +* +c - grfcon - +f - GRFCON = INTEGER (Given) - +* A KeyMap containing information passed from the calling application. + +* Line: +* The "Line" function displays lines joining the given positions and +* requires the following interface: +* +c int Line( AstObject *grfcon, int n, const float *x, const float *y ) +f INTEGER FUNCTION LINE( GRFCON, N, X, Y ) +* +c - grfcon - +f - GRFCON = INTEGER (Given) - +* A KeyMap containing information passed from the calling application. +c - n - The number of positions to be joined together. +f - N = INTEGER (Given) - The number of positions to be joined together. +c - x - A pointer to an array holding the "n" x values. +f - X( N ) = REAL (Given) - An array holding the "n" x values. +c - y - A pointer to an array holding the "n" y values. +f - Y( N ) = REAL (Given) - An array holding the "n" y values. + +* Mark: +* The "Mark" function displays markers at the given positions. It +* requires the following interface: +* +c int Mark( AstObject *grfcon, int n, const float *x, const float *y, int type ) +f INTEGER FUNCTION MARK( GRFCON, N, X, Y, TYPE ) +* +c - grfcon - +f - GRFCON = INTEGER (Given) - +* A KeyMap containing information passed from the calling application. +c - n - The number of positions to be marked. +f - N = INTEGER (Given) - The number of positions to be marked. +c - x - A pointer to an array holding the "n" x values. +f - X( N ) = REAL (Given) - An array holding the "n" x values. +c - y - A pointer to an array holding the "n" y values. +f - Y( N ) = REAL (Given) - An array holding the "n" y values. +c - type - An integer which can be used to indicate the type of marker +c symbol required. +f - TYPE = INTEGER (Given) - An integer which can be used to indicate +f the type of marker symbol required. + +* Qch: +* The "Qch" function returns the heights of characters drawn vertically +* and horizontally in graphics coordinates. It requires the following +* interface: +* +c int Qch( AstObject *grfcon, float *chv, float *chh ) +f INTEGER FUNCTION QCH( GRFCON, CHV, CHH ) +* +c - grfcon - +f - GRFCON = INTEGER (Given) - +* A KeyMap containing information passed from the calling application. +c - chv - A pointer to the float which is to receive the height of +f - CHV = REAL (Returned) The height of +* characters drawn with a vertical baseline. This will be an +* increment in the X axis. +c - chh - A pointer to the float which is to receive the height of +f - CHH = REAL (Returned) The height of +* characters drawn with a horizontal baseline. This will be an +* increment in the Y axis. + +* Scales: +* The "Scales" function returns two values (one for each axis) which +* scale increments on the corresponding axis into a "normal" coordinate +* system in which: 1) the axes have equal scale in terms of (for instance) +* millimetres per unit distance, 2) X values increase from left to +* right, and 3) Y values increase from bottom to top. It requires the +* following interface: +* +c int Scales( AstObject *grfcon, float *alpha, float *beta ) +f INTEGER FUNCTION SCALES( GRFCON, ALPHA, BETA ) +* +c - grfcon - +f - GRFCON = INTEGER (Given) - +* A KeyMap containing information passed from the calling application. +c - alpha - A pointer to the float which is to receive the +f - ALPHA = REAL (Returned) The +* scale for the X axis (i.e. Xnorm = alpha*Xworld). +c - beta - A pointer to the float which is to receive the +f - BETA = REAL (Returned) The +* scale for the Y axis (i.e. Ynorm = beta*Yworld). + +* Text: +* The "Text" function displays a character string at a given +* position using a specified justification and up-vector. It +* requires the following interface: +* +c int Text( AstObject *grfcon, const char *text, float x, float y, const char *just, +c float upx, float upy ) +f INTEGER FUNCTION TEXT( GRFCON, TEXT, X, Y, JUST, UPX, UPY ) +* +c - grfcon - +f - GRFCON = INTEGER (Given) - +* A KeyMap containing information passed from the calling application. +c - text - Pointer to a null-terminated character string to be displayed. +f - TEXT = CHARACTER * ( * ) (Given) - The string to be displayed. +c - x - The reference x coordinate. +f - X = REAL (Given) - The reference x coordinate. +c - y - The reference y coordinate. +f - Y = REAL (Given) - The reference y coordinate. +c - just - A character string which specifies the location within the +f - JUST = CHARACTER * ( * ) (Given ) - A string which specifies the +f location within the +* text string which is to be placed at the reference position +* given by x and y. The first character may be 'T' for "top", +* 'C' for "centre", or 'B' for "bottom", and specifies the +* vertical location of the reference position. Note, "bottom" +* corresponds to the base-line of normal text. Some characters +* (eg "y", "g", "p", etc) descend below the base-line. The second +* character may be 'L' for "left", 'C' for "centre", or 'R' +* for "right", and specifies the horizontal location of the +* reference position. If the string has less than 2 characters +* then 'C' is used for the missing characters. +c - upx - The x component of the up-vector for the text. +f - UPX = REAL (Given) - The x component of the up-vector for the text. +* If necessary the supplied value should be negated +* to ensure that positive values always refer to displacements from +* left to right on the screen. +c - upy - The y component of the up-vector for the text. +f - UPX = REAL (Given) - The y component of the up-vector for the text. +* If necessary the supplied value should be negated +* to ensure that positive values always refer to displacements from +* bottom to top on the screen. + +* TxExt: +* The "TxExt" function returns the corners of a box which would enclose +* the supplied character string if it were displayed using the +* Text function described above. The returned box includes any leading +* or trailing spaces. It requires the following interface: +* +c int TxExt( AstObject *grfcon, const char *text, float x, float y, const char *just, +c float upx, float upy, float *xb, float *yb ) +f INTEGER FUNCTION TXEXT( GRFCON, TEXT, X, Y, JUST, UPX, UPY, XB, YB ) +* +c - grfcon - +f - GRFCON = INTEGER (Given) - +* A KeyMap containing information passed from the calling application. +c - text - Pointer to a null-terminated character string to be displayed. +f - TEXT = CHARACTER * ( * ) (Given) - The string to be displayed. +c - x - The reference x coordinate. +f - X = REAL (Given) - The reference x coordinate. +c - y - The reference y coordinate. +f - Y = REAL (Given) - The reference y coordinate. +c - just - A character string which specifies the location within the +f - JUST = CHARACTER * ( * ) (Given ) - A string which specifies the +f location within the +* text string which is to be placed at the reference position +* given by x and y. See "Text" above. +c - upx - The x component of the up-vector for the text. +f - UPX = REAL (Given) - The x component of the up-vector for the text. +* See "Text" above. +c - upy - The y component of the up-vector for the text. +f - UPX = REAL (Given) - The y component of the up-vector for the text. +* See "Text" above. +c - xb - An array of 4 elements in which to return the x coordinate of +f - XB( 4 ) = REAL (Returned) - Returned holding the x coordinate of +* each corner of the bounding box. +c - yb - An array of 4 elements in which to return the y coordinate of +f - YB( 4 ) = REAL (Returned) - Returned holding the y coordinate of +* each corner of the bounding box. + +*-- +*/ + +/* Local Variables: */ + const char *class; /* Object class */ + const char *method; /* Current method */ + int ifun; /* Index into grf function list */ + void (* wrapper)(); /* Wrapper function for C Grf routine*/ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + wrapper = NULL; + +/* Store the current method and class for inclusion in error messages + generated by lower level functions. */ + method = "astGrfSet"; + class = astClass( this ); + +/* Identify the supplied function name and get its integer index into the + list of grf functions. */ + ifun = astGrfFunID( name, method, class ); + +/* Store the pointer. */ + if( astOK ) { + this->grffun[ifun] = fun; + +/* In general, the interface to each Grf function will differ for + different languages. So we need a wrapper function with a known fixed + interface which can be used to invoke the actual Grf function with + an interface suited to the language in use. Call astGrfWrapper to store + a wrapper to a suitable function which can invoke the supplied + grf function. Here, we assume that the supplied function has a C + interface, so we set up a C wrapper. If this function is being called + from another language, then the interface for this function within + that language should set up an appropriate wrapper after calling this + function, thus over-riding the C wrapper set up here. */ + if( ifun == AST__GATTR ) { + wrapper = (AstGrfWrap) CGAttrWrapper; + + } else if( ifun == AST__GBBUF ) { + wrapper = (AstGrfWrap) CGBBufWrapper; + + } else if( ifun == AST__GEBUF ) { + wrapper = (AstGrfWrap) CGEBufWrapper; + + } else if( ifun == AST__GFLUSH ) { + wrapper = (AstGrfWrap) CGFlushWrapper; + + } else if( ifun == AST__GLINE ) { + wrapper = (AstGrfWrap) CGLineWrapper; + + } else if( ifun == AST__GMARK ) { + wrapper = (AstGrfWrap) CGMarkWrapper; + + } else if( ifun == AST__GTEXT ) { + wrapper = (AstGrfWrap) CGTextWrapper; + + } else if( ifun == AST__GCAP ) { + wrapper = (AstGrfWrap) CGCapWrapper; + + } else if( ifun == AST__GTXEXT ) { + wrapper = (AstGrfWrap) CGTxExtWrapper; + + } else if( ifun == AST__GSCALES ) { + wrapper = (AstGrfWrap) CGScalesWrapper; + + } else if( ifun == AST__GQCH ) { + wrapper = (AstGrfWrap) CGQchWrapper; + + } else if( astOK ) { + astError( AST__INTER, "%s(%s): AST internal programming error - " + "Grf function id %d not yet supported.", status, method, class, + ifun ); + } + astGrfWrapper( this, name, wrapper ); + } +} + +int astGrfFunID_( const char *name, const char *method, const char *class, int *status ) { +/* +*+ +* Name: +* astGrfFunID + +* Purpose: +* Return the integer identifier for a given GRF routine. + +* Type: +* Hidden public function. + +* Synopsis: +* #include "plot.h" +* int astGrfFunID( const char *name, const char *method, +* const char *class ) + +* Class Membership: +* Plot member function. + +* Description: +* This function returns an integer identifying the named grf function. +* An error is reported if the named function is unknown. This function +* is used by non-class modules within AST (e.g. fplot.c) which is why +* it is public. It is not intended to be used by the public. + +* Parameters: +* name +* The grf function name. Any unambiguous abbreviation will do. +* Case is ignored. The full list of grf function names is: +* "Attr BBuf EBuf Scales Flush Line Mark Qch Text TxExt". See +* grf_pgplot.c for details of these functions. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. + +*- +*/ + +/* Note that the list of identifiers here must be in the same order as the + sorted values of the constants AST__GATTR, AST__GFLUSH, etc */ + return FullForm( "Attr Flush Line Mark Text TxExt Scales Qch Cap BBuf " + "EBuf", name, "Grf function name (programming error)", + method, class, status ); +} + +static char *GrfItem( int item, const char *text, int *axis, int *status ){ +/* +* Name: +* GrfItem + +* Purpose: +* Return the textual name corresponding to a specified graphical item +* index. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* char *GrfItem( int item, const char *text, int *axis, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function returns a textual description of the graphical item +* with the supplied index. + +* Parameters: +* item +* The index of the graphical item. +* text +* A pointer to a string which will be appended to the textual +* description of the graphical item. May be NULL. +* axis +* Pointer to a place in which to return the index (0,1, or 2) of +* the axis to which the attribute refers, If the attribute does +* not refer to a specific axis, -1 is returned. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to a dynamically allocated string holding the textual +* description of the graphical item, followed by any supplied "text". + +* Notes: +* - An error is reported and a NULL pointer returned if the +* index does not correspond to any graphical item. +* - The returned pointer should be freed using astFree when it is no +* longer needed. +* - This function attempts to execute even if an error has already +* occurred. + +*/ + +/* Local Variables: */ + char *desc; /* Pointer to the item description */ + char *ret; /* Pointer to the returned string */ + int dlen; /* Length of the item description */ + + if( axis ) *axis = -1; + + if( item == AST__BORDER_ID ) { + desc = "Border"; + + } else if ( item == AST__GRIDLINE_ID ) { + desc = "Gridline"; + + } else if ( item == AST__GRIDLINE1_ID ) { + desc = "Axis 1 gridline"; + if( axis ) *axis = 0; + + } else if ( item == AST__GRIDLINE2_ID ) { + desc = "Axis 2 gridline"; + if( axis ) *axis = 1; + + } else if ( item == AST__GRIDLINE3_ID ) { + desc = "Axis 3 gridline"; + if( axis ) *axis = 2; + + } else if ( item == AST__CURVE_ID ) { + desc = "Curve"; + + } else if ( item == AST__NUMLABS_ID ) { + desc = "Numerical labels"; + + } else if ( item == AST__TEXTLABS_ID ) { + desc = "Textual labels"; + + } else if ( item == AST__TITLE_ID ) { + desc = "Title"; + + } else if ( item == AST__MARKS_ID ) { + desc = "Markers"; + + } else if ( item == AST__TEXT_ID ) { + desc = "Text string"; + + } else if ( item == AST__TICKS_ID ) { + desc = "Major and minor ticks"; + + } else if ( item == AST__AXIS1_ID ) { + desc = "Axis 1"; + if( axis ) *axis = 0; + + } else if ( item == AST__AXIS2_ID ) { + desc = "Axis 2"; + if( axis ) *axis = 1; + + } else if ( item == AST__AXIS3_ID ) { + desc = "Axis 3"; + if( axis ) *axis = 2; + + } else if ( item == AST__NUMLAB1_ID ) { + desc = "Axis 1 numerical labels"; + if( axis ) *axis = 0; + + } else if ( item == AST__NUMLAB2_ID ) { + desc = "Axis 2 numerical labels"; + if( axis ) *axis = 1; + + } else if ( item == AST__NUMLAB3_ID ) { + desc = "Axis 3 numerical labels"; + if( axis ) *axis = 2; + + } else if ( item == AST__TEXTLAB1_ID ) { + desc = "Axis 1 textual label"; + if( axis ) *axis = 0; + + } else if ( item == AST__TEXTLAB2_ID ) { + desc = "Axis 2 textual label"; + if( axis ) *axis = 1; + + } else if ( item == AST__TEXTLAB3_ID ) { + desc = "Axis 3 textual label"; + if( axis ) *axis = 2; + + } else if ( item == AST__TICKS1_ID ) { + desc = "Axis 1 tick marks"; + if( axis ) *axis = 0; + + } else if ( item == AST__TICKS2_ID ) { + desc = "Axis 2 tick marks"; + if( axis ) *axis = 1; + + } else if ( item == AST__TICKS3_ID ) { + desc = "Axis 3 tick marks"; + if( axis ) *axis = 2; + + } else { + desc = NULL; + if( astOK ){ + astError( AST__INTER, "GrfItem: AST internal programming error - " + "Invalid graphical item index %d supplied to GrfItem.", status, + item ); + } + } + + if( desc ) { + dlen = strlen( desc ); + + if( text ) { + ret = astStore( NULL, desc, dlen + strlen( text ) + 1 ); + if( ret ) strcpy( ret + dlen, text ); + } else { + ret = astStore( NULL, desc, dlen + 1 ); + } + + } else { + ret = NULL; + } + +/* Return the answer. */ + return ret; +} + +static void GrfWrapper( AstPlot *this, const char *name, AstGrfWrap wrapper, int *status ) { +/* +*+ +* Name: +* astGrfWrapper + +* Purpose: +* Register a wrapper function for a F77 or C Grf function. + +* Type: +* Protected function. + +* Synopsis: +* #include "plot.h" +* void astGrfWrapper( AstPlot *this, const char *name, AstGrfWrap wrapper) + +* Description: +* This function stores a pointer to the supplied wrapper function +* within the plot, associating it with the grf function indicated by +* the "name" parameter. The supplied wrapper function should call the +* named grf function, using an interface appropriate to the language +* in which the grf function is written. + +* Parameters: +* this +* The plot. +* name +* A name indicating the graphics function which is called by the +* supplied wrapper function. See astGrfSet for details. +* wrapper +* A pointer to the wrapper function. This will be cast to a +* specific type for the named grf function before being store +* in the Plot. +*- +*/ + +/* Local Variables: */ + const char *class; /* Object class */ + const char *method; /* Current method */ + int ifun; /* Index into grf function list */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Store the current method and class for inclusion in error messages + generated by lower level functions. */ + method = "astGrfWrapper"; + class = astClass( this ); + +/* Identify the supplied function name and get its integer index into the + list of grf functions. */ + ifun = astGrfFunID( name, method, class ); + +/* Cast the wrapper to an interface appropriate for the wrapped grf + function, and store it in the appropriate component of the Plot. */ + if( ifun == AST__GATTR ) { + this->GAttr = (AstGAttrWrap) wrapper; + + } else if( ifun == AST__GBBUF ) { + this->GBBuf = (AstGBBufWrap) wrapper; + + } else if( ifun == AST__GEBUF ) { + this->GEBuf = (AstGEBufWrap) wrapper; + + } else if( ifun == AST__GFLUSH ) { + this->GFlush = (AstGFlushWrap) wrapper; + + } else if( ifun == AST__GLINE ) { + this->GLine = (AstGLineWrap) wrapper; + + } else if( ifun == AST__GMARK ) { + this->GMark = (AstGMarkWrap) wrapper; + + } else if( ifun == AST__GTEXT ) { + this->GText = (AstGTextWrap) wrapper; + + } else if( ifun == AST__GCAP ) { + this->GCap = (AstGCapWrap) wrapper; + + } else if( ifun == AST__GTXEXT ) { + this->GTxExt = (AstGTxExtWrap) wrapper; + + } else if( ifun == AST__GSCALES ) { + this->GScales = (AstGScalesWrap) wrapper; + + } else if( ifun == AST__GQCH ) { + this->GQch = (AstGQchWrap) wrapper; + + } else if( astOK ) { + astError( AST__INTER, "%s(%s): AST internal programming error - " + "Grf function id %d not yet supported.", status, method, class, + ifun ); + } +} + +static void Grid( AstPlot *this_nd, int *status ){ +/* +*++ +* Name: +c astGrid +f AST_GRID + +* Purpose: +* Draw a set of labelled coordinate axes. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "plot.h" +c void astGrid( AstPlot *this ) +f CALL AST_GRID( THIS, STATUS ) + +* Class Membership: +* Plot method. + +* Description: +c This function draws a complete annotated set of +f This routine draws a complete annotated set of +* coordinate axes for a Plot with (optionally) a coordinate grid +* superimposed. Details of the axes and grid can be controlled by +* setting values for the various attributes defined by the Plot +* class (q.v.). + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +* - If the supplied Plot is a Plot3D, the axes will be annotated +* using three 2-dimensional Plots, one for each 2D plane in the 3D +* current coordinate system. The plots will be "pasted" onto 3 faces +* of the cuboid graphics volume specified when the Plot3D was +* constructed. The faces to be used can be controlled by the "RootCorner" +* attribute. +* - An error results if either the current Frame or the base Frame +* of the Plot is not 2-dimensional or (for a Plot3D) 3-dimensional. +* - An error also results if the transformation between the base +* and current Frames of the Plot is not defined in either +* direction (i.e. the Plot's TranForward or TranInverse attribute +* is zero). +*-- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstPlot *this; /* Plot with 2d current Frame */ + AstPlotCurveData **cdata;/* Pointer to info. about breaks in curves */ + TickInfo **grid; /* Pointer to info. about tick marks */ + const char *class; /* Object class */ + const char *method; /* Current method */ + double cen[ 2 ]; /* Position of first tick mark */ + double gap[ 2 ]; /* Gap between tick marks */ + double labelat[ 2 ]; /* Axis values at which tick marks are put */ + int axis; /* Physical axis index */ + int border; /* Draw a border? */ + int clip; /* Original Clip attribute value */ + int dounits[2]; /* Include Units in each axis label? */ + int drawgrid; /* Is a grid of lines to be drawn? */ + int clredge; /* Clear the Edge attributes before returning? */ + int edgeticks; /* Draw labels round edges of plotting area? */ + int escs; /* Original astEscapes value */ + int ink; /* Draw the grid with visible ink? */ + int inval; /* Were areas of invalid coordinates found? */ + int labelling; /* Value of Labelling attribute */ + int loglabelset[2]; /* Were the LogLabel attributes set initially? */ + int logticksset[2]; /* Were the LogTicks attributes set initially? */ + int naxes; /* No. of axes in the base or current Frame */ + int oldedge0; /* Default value for Edge(1) */ + int oldedge1; /* Default value for Edge(2) */ + int useint; /* Do interior labels give us an advantage? */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this_nd); + +/* Store the current method and class for inclusion in error messages + generated by lower level functions. */ + method = "astGrid"; + class = astClass( this_nd ); + +/* Check the base Frame of the Plot is 2-D. */ + naxes = astGetNin( this_nd ); + if( naxes != 2 && astOK ){ + astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " + "Frame of the supplied %s is invalid - this number should " + "be 2.", status, method, class, naxes, class ); + } + +/* Ensure AST functions included graphical escape sequences in any + returned text strings. */ + escs = astEscapes( 1 ); + +/* Note if attributes which have complex dynamic defaults are set + initially. */ + logticksset[0] = astTestLogTicks( this_nd, 0 ); + logticksset[1] = astTestLogTicks( this_nd, 1 ); + loglabelset[0] = astTestLogLabel( this_nd, 0 ); + loglabelset[1] = astTestLogLabel( this_nd, 1 ); + +/* Indicate that the GRF module should re-calculate it's cached values + (in case the state of the graphics system has changed since the last + thing was drawn). */ + RESET_GRF; + +/* Get a Plot with a 2D (or 1D) current Frame. */ + this = (AstPlot *) Fset2D( (AstFrameSet *) this_nd, AST__CURRENT, status ); + +/* Check the current Frame of the Plot is 2-D. */ + naxes = astGetNout( this ); + if( naxes != 2 && astOK ){ + astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the current " + "Frame of the supplied %s is invalid - this number should " + "be 2.", status, method, class, naxes, class ); + } + +/* Ensure that all lines are clipped at the plot boundary.*/ + if( astTestClip( this ) ) { + clip = astGetClip( this ); + astSetClip( this, 1 ); + } else { + clip = -1; + } + +/* If the protected attribute "Ink" is set to zero, then the plot + is drawn in "invisble ink" (i.e. all the calculations needed to + produce the grid are performed, but nothing is actually drawn). */ + ink = astGetInk( this ); + +/* Initialise the bounds of the box containing all plotted lines and + numerical labels. */ + Box_lbnd[ 0 ] = FLT_MAX; + Box_lbnd[ 1 ] = FLT_MAX; + Box_ubnd[ 0 ] = FLT_MIN; + Box_ubnd[ 1 ] = FLT_MIN; + +/* Obtain the requested centre attribute values for both physical axes. */ + for( axis = 0; axis < 2; axis++ ){ + cen[ axis ] = astGetCentre( this, axis ); + } + +/* Determine where to put the major axis values. */ + grid = GridLines( this, cen, gap, &inval, method, class, status ); + +/* If the user has set an explicit value for Grid, use it. */ + if( astTestGrid( this ) ){ + drawgrid = astGetGrid( this ); + +/* If not, the default for Grid is based on whether or not there are any + invalid regions. */ + } else if( inval ){ + drawgrid = 1; + + } else { + drawgrid = 0; + } + +/* Draw the curves marking the major tick values on each axis. Information + is returned describing the positions of the breaks in these curves. */ + cdata = DrawGrid( this, grid, ( ink && drawgrid ), method, class, status ); + +/* See if labels and tick marks will be drawn round the edges of the + plotting area, rather than within it (no labels are actually drawn + yet). Interior labels can always be produced, in which case edgeticks + is set explicitly to zero to indicate that ticks will be internal. + Exterior labelling may or may not be possible. If it is requested, + check to see if it is possible. */ + clredge = 0; + labelling = astGetLabelling( this ); + if( labelling ){ + edgeticks = 0; + } else { + edgeticks = EdgeLabels( this, 0, grid, cdata, 0, method, class, status ); + +/* If the external labelling was requested, but could not be produced... */ + if( !edgeticks ) { + +/* and if the Edge attributes have not been set... */ + if( !astTestEdge( this, 0 ) && !astTestEdge( this, 1 ) ) { + +/* Try flipping the default Edge values, to see if this allows us to + honour the requested Labelling scheme. */ + oldedge0 = astGetEdge( this, 0 ); + oldedge1 = astGetEdge( this, 1 ); + astSetEdge( this, 0, oldedge1 ); + astSetEdge( this, 1, oldedge0 ); + +/* See if exterior labels could be drawn with these new edges. */ + edgeticks = EdgeLabels( this, 0, grid, cdata, 0, method, class, status ); + +/* If this would allow us to use the requested labelling scheme, retain + the new Edge values, setting a flag to indicate that they will need to be + cleared before returning. Otherwise, clear them. */ + if( edgeticks ) { + clredge = 1; + + } else { + astClearEdge( this, 0 ); + astClearEdge( this, 1 ); + } + } + } + } + +/* If edge ticks can still not be produced, but the ForceExterior attribute + has a non-zero value, attempt to create exterior labels even though it + looks like there may be insufficient of them to justify their use. */ + if( !edgeticks && astGetForceExterior( this ) ) { + edgeticks = EdgeLabels( this, 0, grid, cdata, 1, method, class, status ); + } + +/* We may also need to swap edge values when using interior labelling in + order to ensure that the text labels are placed on appropriate edges of + the plotting box. */ + if( !edgeticks && !astTestEdge( this, 0 ) && !astTestEdge( this, 1 ) ) { + if( swapEdges( this, grid, cdata, status ) ) { + oldedge0 = astGetEdge( this, 0 ); + oldedge1 = astGetEdge( this, 1 ); + astSetEdge( this, 0, oldedge1 ); + astSetEdge( this, 1, oldedge0 ); + clredge = 1; + } + } + +/* If edge ticks are being used, store bad values for the labelat values to + indicate that labels are not being drawn within the interior of the + plotting area. */ + if( edgeticks ){ + labelat[ 0 ] = AST__BAD; + labelat[ 1 ] = AST__BAD; + +/* Otherwise, see where interior labels and tick marks should go (the axis + values are put in "labelat"). */ + } else { + useint = Labelat( this, grid, cdata, labelat, method, class, status ); + +/* If interior labelling does not allow us to draw any more ticks, revert + to edge labelling if that is what the user requested. */ + if( !useint && !labelling ) { + labelat[ 0 ] = AST__BAD; + labelat[ 1 ] = AST__BAD; + edgeticks = EdgeLabels( this, 0, grid, cdata, 1, method, class, status ); + } + } + +/* See if a border is required. By default, a border is drawn only when + using exterior labelling. */ + if( astTestBorder( this ) ) { + border = astGetBorder( this ); + } else { + border = edgeticks; + } + +/* See if the Units string is to be inluded in the label. */ + dounits[ 0 ] = astGetLabelUnits( this, 0 ); + dounits[ 1 ] = astGetLabelUnits( this, 1 ); + +/* The rest is not done if no output is required. */ + if( ink ) { + +/* Draw tick marks (major and minor). */ + DrawTicks( this, grid, drawgrid, labelat, gap, method, class, status ); + +/* If required, ensure that curves through the tick marks have been drawn */ + DrawAxis( this, grid, labelat, gap, method, class, status ); + +/* If required, draw a curve around the edge of the area containing valid + physical coordinates. */ + if( border ) (void) astBorder( this ); + +/* Draw the numerical labels at the major tick values. */ + Labels( this, grid, cdata, gap, labelat, method, class, status ); + +/* Draw the textual labels for each axis and a title. */ + TextLabels( this, edgeticks, dounits, method, class, status ); + } + +/* Ensure all lines are flushed to the graphics system. */ + Fpoly( this, method, class, status ); + +/* Store the actual values used for all attributes which have dynamic + defaults. Check the global status to ensure the pointer "grid" can be + used without the possibility of a segmentation violation. */ + for( axis = 0; axis < 2 && astOK ; axis++ ) { + SetUsedLogTicks( this_nd, axis, astGetLogTicks( this, axis ), status ); + SetUsedLogLabel( this_nd, axis, astGetLogLabel( this, axis ), status ); + + if( astGetLogTicks( this, axis ) ) { + SetUsedLogGap( this_nd, axis, gap[ axis ], status ); + } else { + SetUsedGap( this_nd, axis, gap[ axis ], status ); + } + SetUsedCentre( this_nd, axis, cen[ axis ], status ); + SetUsedEdge( this_nd, axis, astGetEdge( this, axis ), status ); + SetUsedLabelAt( this_nd, axis, labelat[ axis ], status ); + SetUsedLabelUnits( this_nd, axis, dounits[ axis ], status ); + +/* If explicit minor tick values were supplied using astSetTickValues, + then set MinTick to the average number of minor tick divisions per major + tick division. */ + if( grid[ axis ]->minticks ) { + SetUsedMinTick( this_nd, axis, + ( grid[ axis ]->nminor + grid[ axis ]->nmajor )/ + ( grid[ axis ]->nmajor - 1 ), status ); + } else { + SetUsedMinTick( this_nd, axis, grid[ axis ]->nminor, status ); + } + + if( astTestTextLab( this, axis ) ) { + SetUsedTextLab( this_nd, axis, astGetTextLab( this, axis ), status ); + } else { + SetUsedTextLab( this_nd, axis, edgeticks, status ); + } + + if( astTestMajTickLen( this, axis ) ) { + SetUsedMajTickLen( this_nd, axis, astGetMajTickLen( this, axis ), status ); + } else { + SetUsedMajTickLen( this_nd, axis, drawgrid ? 0.0 : + astGetMajTickLen( this, axis ), status ); + } + + } + + SetUsedGrid( this_nd, drawgrid, status ); + SetUsedLabelling( this_nd, edgeticks ? 0 : 1, status ); + SetUsedBorder( this_nd, border, status ); + +/* Free the memory used to hold information about the curves. */ + cdata = CleanCdata( cdata, status ); + +/* Free the memory used to hold information about the tick marks. */ + grid = CleanGrid( grid, status ); + +/* If required clear attributes. */ + if( clredge ) { + astClearEdge( this, 0 ); + astClearEdge( this, 1 ); + } + + if( !logticksset[ 0 ] ) astClearLogTicks( this, 0 ); + if( !logticksset[ 1 ] ) astClearLogTicks( this, 1 ); + if( !loglabelset[ 0 ] ) astClearLogLabel( this, 0 ); + if( !loglabelset[ 1 ] ) astClearLogLabel( this, 1 ); + +/* Restore the original value of the Clip attribute. */ + if( clip != -1 ) astSetClip( this, clip ); + +/* Free the 2D Plot. */ + this = astAnnul( this ); + +/* Restore the original value of the flag which says whether graphical + escape sequences should be incldued in any returned text strings. */ + astEscapes( escs ); + +/* Copy the total bounding box to the box which is returned by + astBoundingBox. */ + if( !Boxp_freeze ){ + Boxp_lbnd[ 0 ] = Box_lbnd[ 0 ]; + Boxp_lbnd[ 1 ] = Box_lbnd[ 1 ]; + Boxp_ubnd[ 0 ] = Box_ubnd[ 0 ]; + Boxp_ubnd[ 1 ] = Box_ubnd[ 1 ]; + } + +/* Return. */ + return; + +} + +static void GridLine( AstPlot *this, int axis, const double start[], + double length, int *status ){ +/* +*++ +* Name: +c astGridLine +f AST_GRIDLINE + +* Purpose: +* Draw a grid line (or axis) for a Plot. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "plot.h" +c void astGridLine( AstPlot *this, int axis, const double start[], +c double length ) +f CALL AST_GRIDLINE( THIS, AXIS, START, LENGTH, STATUS ) + +* Class Membership: +* Plot method. + +* Description: +c This function draws a curve in the physical coordinate system of +f This routine draws a curve in the physical coordinate system of +* a Plot by varying only one of the coordinates along the length +* of the curve. It is intended for drawing coordinate axes, +* coordinate grids, and tick marks on axes (but note that these +c are also available via the more comprehensive astGrid function). +f are also available via the more comprehensive AST_GRID routine). +* +* The curve is transformed into graphical coordinate space for +* plotting, so that a straight line in physical coordinates may +* result in a curved line being drawn if the Mapping involved is +* non-linear. Any discontinuities in the Mapping between physical +* and graphical coordinates are catered for, as is any +c clipping established using astClip. +f clipping established using AST_CLIP. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +c axis +f AXIS = INTEGER (Given) +* The index of the Plot axis whose physical coordinate value is +* to be varied along the length of the curve (all other +* coordinates will remain fixed). This value should lie in the +* range from 1 to the number of Plot axes (Naxes attribute). +c start +f START( * ) = DOUBLE PRECISION (Given) +* An array, with one element for each axis of the Plot, giving +* the physical coordinates of the start of the curve. +c length +f LENGTH = DOUBLE PRECISION (Given) +* The length of curve to be drawn, given as an increment along +* the selected physical axis. This may be positive or negative. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +c - No curve is drawn if the "start" array contains any +c coordinates with the value AST__BAD, nor if "length" has this value. +f - No curve is drawn if the START array contains any +f coordinates with the value AST__BAD, nor if LENGTH has this value. +* - An error results if the base Frame of the Plot is not 2-dimensional. +* - An error also results if the transformation between the +* current and base Frames of the Plot is not defined (i.e. the +* Plot's TranInverse attribute is zero). +*-- +*/ +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + const char *class; /* Object class */ + const char *method; /* Current method */ + int naxes; /* No. of axes in the base Frame */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Store the current method, and the class of the supplied object for use + in error messages.*/ + method = "astGridLine"; + class = astGetClass( this ); + +/* Check the base Frame of the Plot is 2-D. */ + naxes = astGetNin( this ); + if( naxes != 2 && astOK ){ + astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " + "Frame of the supplied %s is invalid - this number should " + "be 2.", status, method, class, naxes, class ); + } + +/* Initialise the bounding box for primatives produced by this call. */ + if( !Boxp_freeze ) { + Boxp_lbnd[ 0 ] = FLT_MAX; + Boxp_lbnd[ 1 ] = FLT_MAX; + Boxp_ubnd[ 0 ] = FLT_MIN; + Boxp_ubnd[ 1 ] = FLT_MIN; + } + +/* Validate the axis index, converting the axis index to be zero-based. */ + (void) astValidateAxis( this, axis - 1, 1, method ); + +/* Indicate that the GRF module should re-calculate it's cached values + (in case the state of the graphics system has changed since the last + thing was drawn). */ + RESET_GRF; + +/* Draw the curve. The break information is stored in an external structure + where it can be accessed by public methods which return information + about the most recently drawn curve. */ + AxPlot( this, axis - 1, start, length, 1, &Curve_data, method, class, status ); + +/* Ensure all lines are flushed to the graphics system. */ + Fpoly( this, method, class, status ); +} + +static TickInfo **GridLines( AstPlot *this, double *cen, double *gap, + int *inval, const char *method, const char *class, int *status ){ +/* +* Name: +* GridLines + +* Purpose: +* Obtain information desribing the major tick values within the plotting +* area. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* TickInfo **GridLines( AstPlot *this, double *cen, double *gap, +* int *inval, const char *method, const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* A pointer is returned which points to an array of two pointers. Each +* of these pointers points to a TickInfo structure which holds +* information about the ticks on a single axis. These structures, +* together with the array holding the two pointers, should be released +* when no longer needed using CleanGrid. + +* Parameters: +* this +* The Plot. +* cen +* A pointer to an array holding axis values at which to put a single +* central tick. Other ticks are placed evenly on either side of this +* tick. If AST__BAD is provided, a value will be used which would put a +* tick at an axis value of zero. +* gap +* A pointer to an array holding the gaps between ticks required on +* each axis. If this is AST__BAD a suitable default value will be used +* and returned in place of the AST__BAD value. +* inval +* A pointer to a location at which to return a flag indicating if +* any invalid physical coordinates were encountered while deciding on +* the tick values. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to an array of two TickInfo pointers. + +* Notes: +* - This function assumes that the physical coordinate system is 2 +* dimensional, and it should not be used if this is not the case. +* - If an error has already occurred, or if this function should fail +* for any reason, then a NULL pointer is returned. +*/ + +/* Local Variables: */ + AstFrame *fr; /* Pointer to current Frame */ + GetTicksStatics *statics = NULL; /* Pointer to static data for GetTicks */ + TickInfo **info; /* Returned array of two TickInfo pointers */ + double *lengths; /* Pointer to lengths of each curve section */ + double *starts; /* Pointer to start of each curve section */ + double *ticks; /* Pointer to tick mark values */ + double bot; /* Lowest axis value to display */ + double end; /* Axis value at end of curve section */ + double tmp; /* Temp storage */ + double top; /* Highest axis value to display */ + int i; /* Tick mark index */ + int j; /* Axis index */ + int k; /* Section index */ + int logticks[ 2 ]; /* Uses logarithmicaly spaced tick marks? */ + int nticks; /* Number of tick marks */ + +/* Check the global status. */ + if( !astOK ) return NULL; + +/* Get memory to hold two TickInfo pointers. */ + info = (TickInfo **) astMalloc( 2*sizeof( TickInfo *) ); + +/* If succesfull... */ + if( astOK ){ + +/* Initialise the two pointers. */ + info[ 0 ] = NULL; + info[ 1 ] = NULL; + +/* Obtain the tick mark values, and the corresponding formatted labels for + each axis. */ + for( j = 0; j < 2; j++ ){ + info[ j ] = TickMarks( this, j, cen + j, gap + j, inval, + &statics, method, class, status ); + logticks[ j ] = astGetLogTicks( this, j ); + } + +/* Release the resources allocated in the first call to TickMarks. */ + for( j = 0; j < 2; j++ ){ + (void) TickMarks( NULL, j, NULL, gap, NULL, &statics, method, class, + status ); + } + +/* Each major tick value for axis "j" may be marked with a curve parallel + to axis "1-j" drawn across the entire plotting area. We need to decide + where to start drawing this curve and how long it should be. We can + simply use the minimum value on axis "1-j" together with the tick value + on axis "j" to define the starting position. The length could be taken + as the difference between the maximum and minimum values on axis "1-j". + However, this may not be right in some situations. For instance if the + plotting area covers a small range of Right Ascension from 23:59:59 to + 00:00:01. Using the difference between the maximum and minimum values + to give the length of the curve would result in the curve starting at + 00:00:00 (the minimum axis value) and extending for a length of 23:59:59 + (the axis range). To get round this sort of problem, the curve is split + up into sections with lengths and starting positions determined by the + tick mark values on axis "1-j". The first section starts at the minimum + axis value and extends upto the first missing tick mark (in the RA + example, this would be at 00:00:01). Subsequent sections starts at the + next tick mark (23:59:59 in the RA example) and extends upto the next + missing tick mark, or the last tick mark if none are missing. */ + +/* Get the current frame. */ + fr = astGetFrame( this, AST__CURRENT ); + +/* If either axis has log tick spacing, use the simple approach which + assumes that each curve has only one section. */ + if( logticks[ 0 ] || logticks[ 1 ] ) { + +/* Find the start and length of the curve for each tick mark on axis "j". */ + for( j = 0; j < 2 && astOK; j++ ){ + +/* Find the axis range to display on the other axis. */ + bot = astGetBottom( fr, 1 - j ); + top = astGetTop( fr, 1 - j ); + if( bot > top ) { + tmp = top; + top = bot; + bot = tmp; + } + +/* Get a pointer to the major tick mark values on the other axis ("1-j"), + together with the number of them. */ + ticks = info[ 1 - j ]->ticks; + nticks = info[ 1 - j ]->nmajor; + +/* Reserve memory to hold the starts and lengths of each section of the + grid line marking the major ticks on the axis "j". There will only be + one section. */ + starts = (double *) astMalloc( sizeof(double) ); + lengths = (double *) astMalloc( sizeof(double) ); + info[ j ]->start = starts; + info[ j ]->length = lengths; + +/* Check that the pointers can be used. */ + if( astOK ) { + +/* The section starts one gap below the first tick, and ends one gap above + the first tick. Limit both to the displayed range of the axis. */ + if( logticks[ 1 - j ] ) { + starts[ 0 ] = astMIN( top, astMAX( bot, ticks[ 0 ]/gap[ 1 - j ] ) ); + end = astMIN( top, astMAX( bot, ticks[ nticks - 1 ]*gap[ 1 - j ] ) ); + } else { + starts[ 0 ] = astMIN( top, astMAX( bot, ticks[ 0 ] - gap[ 1 - j ] ) ); + end = astMIN( top, astMAX( bot, ticks[ nticks - 1 ] + gap[ 1 - j ] ) ); + } + +/* Store the length of the section. */ + lengths[ 0 ] = end - starts[ 0 ]; + +/* Store the number of sections in the returned structure. */ + info[ 0 ]->nsect = 1; + + } + } + +/* If both axes have linear tick spacing, use the complete approach. */ + } else { + +/* Find the start and length of each section of the curve for each tick + mark on axis "j". */ + for( j = 0; j < 2 && astOK; j++ ){ + +/* Find the axis range to display on the other axis. */ + bot = astGetBottom( fr, 1 - j ); + top = astGetTop( fr, 1 - j ); + if( bot > top ) { + tmp = top; + top = bot; + bot = tmp; + } + +/* Get a pointer to the major tick mark values on the other axis ("1-j"), + together with the number of them. */ + ticks = info[ 1 - j ]->ticks; + nticks = info[ 1 - j ]->nmajor; + +/* Reserve memory to hold the starts and lengths of each section of the + grid line marking the major ticks on the axis "j". The allocated + arrays are the largest that could possibly be needed (i.e. if every + tick mark starts a new section). */ + starts = (double *) astMalloc( sizeof(double)*(size_t) nticks ); + lengths = (double *) astMalloc( sizeof(double)*(size_t) nticks ); + info[ j ]->start = starts; + info[ j ]->length = lengths; + +/* Check that the pointers can be used. */ + if( astOK ) { + +/* Loop round each of the major tick marks on axis "1-j". */ + k = 0; + i = 0; + while( i < nticks ){ + +/* Record the start of the next section of the grid lines. */ + starts[ k ] = ticks[ i++ ]; + +/* Tick marks should be regularly spaced by the values in "gap". Check each + tick mark until a missing tick mark is found. The section ends at the + start of the gap. */ + while( i < nticks && + ( ticks[ i ] - ticks[ i - 1 ] ) < 1.5*gap[ 1 - j ] ) i++; + +/* Record the length of the section. */ + lengths[ k ] = ticks[ i - 1 ] - starts[ k ]; + +/* The section is extended at start and end by one gap in order to "cover + up the joins". Limit this to the displayed range of the axis. */ + starts[ k ] -= gap[ 1 - j]; + lengths[ k ] += 2.0*gap[ 1 - j ]; + +/* Limit the start and end to the displayed range of the axis. */ + end = starts[ k ] + lengths[ k ]; + starts[ k ] = astMIN( top, astMAX( bot, starts[ k ] ) ); + lengths[ k ] = astMIN( top, astMAX( bot, end ) ) - starts[ k ]; + +/* Increment the number of sections. */ + k++; + } + +/* Store the number of sections in the returned structure. */ + info[j]->nsect = k; + + } + } + } + +/* Annull the current frame. */ + fr = astAnnul( fr ); + + } + +/* If an error has occurred, clean up the returned TickInfo structures. */ + if( !astOK ) info = CleanGrid( info, status ); + +/* Return. */ + return info; + +} + +void astGrfAttrs_( AstPlot *this, int id, int set, int prim, const char *method, const char *class, int *status ){ +/* +*+ +* Name: +* astGrfAttrs + +* Purpose: +* Establish values for the graphics attributes for a given object. + +* Type: +* Protected function. + +* Synopsis: +* #include "plot.h" +* void astGrfAttrs( AstPlot *this, int id, int set, int prim, const char *method, const char *class ) + +* Class Membership: +* Plot member function. + +* Description: +* This function should be called with "set=1" to establish the correct +* graphics attributes prior to drawing specific graphical objects. Once +* the object has been drawn, it should be called again with "set=0" to +* re-establish the original graphics attributes. +* +* NOTE, each type of graphical object identified by "id" should be +* drawn entirely by calls to just one of GMark, GText or GLine +* as indicated by argument "prim". + +* Parameters: +* this +* A pointer to the Plot. +* id +* An integer specifying the graphical object to be drawn. +* set +* If non-zero then the attributes for the specified object are set +* to the values indicated by the corresponding Plot attributes, +* and the current values are saved in a static array. If zero, then +* the values are set to the values stored in the static array. +* prim +* Indicates the sort of graphics primative used to draw the +* object. This must be one of (defined in grf.h) : +* +* GRF__LINE +* GRF__MARK +* GRF__TEXT +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. + +* Notes: +* - This function should always be called in pairs with set=1 on the +* first call and set=0 on the second call. +* - If a pair of calls is nested within another pair of calls, the +* inner pair has no effect. +*- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + double *attr; /* Pointer to the next attribute value */ + double dval; /* Floating point attribute value */ + int ival; /* Integer attribute value */ + +/* Check the global status. */ + if( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Set up a pointer to the next element in "grfattrs_attrs". */ + attr = grfattrs_attrs; + +/* If we are setting new values, increment the nesting level, otherwise + decrement it. */ + if( set ){ + grfattrs_nesting++; + } else { + grfattrs_nesting--; + } + +/* If we are changing any line attributes, ensure all lines are flushed to + the graphics system. */ + if( prim == GRF__LINE ) Fpoly( this, method, class, status ); + +/* First deal with cases where we are establishing new values for the + graphics attributes by setting them to the values of the corresponding + Plot attributes. Only do this if we are at nesting level one. */ + if( set && grfattrs_nesting == 1 ){ + +/* See if a value has been set in the Plot for the line style attribute for + the specified object, If so, use the value. */ + if( TestUseStyle( this, id, status ) ) { + ival = GetUseStyle( this, id, status ); + +/* Save the current value, and establish the new value. */ + GAttr( this, GRF__STYLE, (double) ival, attr++, prim, method, + class, status ); + +/* If no style was specified, retain the current value. Indicate that no + new value has been established by setting the old value bad. */ + } else { + *(attr++) = AST__BAD; + } + +/* Do the same for the line width attribute. */ + if( TestUseWidth( this, id, status ) ){ + dval = GetUseWidth( this, id, status ); + GAttr( this, GRF__WIDTH, dval, attr++, prim, method, class, status ); + } else { + *(attr++) = AST__BAD; + } + +/* Do the same for the character size attribute. */ + if( TestUseSize( this, id, status ) ) { + dval = GetUseSize( this, id, status ); + GAttr( this, GRF__SIZE, dval, attr++, prim, method, class, status ); + } else { + *(attr++) = AST__BAD; + } + +/* Do the same for the character font attribute. */ + if( TestUseFont( this, id, status ) ){ + ival = GetUseFont( this, id, status ); + GAttr( this, GRF__FONT, (double) ival, attr++, prim, method, class, status ); + } else { + *(attr++) = AST__BAD; + } + +/* Do the same for the colour attribute. */ + if( TestUseColour( this, id, status ) ) { + ival = GetUseColour( this, id, status ); + GAttr( this, GRF__COLOUR, (double) ival, attr++, prim, method, + class, status ); + } else { + *(attr++) = AST__BAD; + } + + } + +/* Now deal with cases where we are re-establishing old values saved on a + previous call to this function. Only do this if we are at nesting + level zero. */ + if( !set && !grfattrs_nesting ){ + GAttr( this, GRF__STYLE, *(attr++), NULL, prim, method, class, status ); + GAttr( this, GRF__WIDTH, *(attr++), NULL, prim, method, class, status ); + GAttr( this, GRF__SIZE, *(attr++), NULL, prim, method, class, status ); + GAttr( this, GRF__FONT, *(attr++), NULL, prim, method, class, status ); + GAttr( this, GRF__COLOUR, *(attr++), NULL, prim, method, class, status ); + } + +/* Return. */ + return; + +} + +static int GVec( AstPlot *this, AstMapping *mapping, double *phy, + int axis, double delta, AstPointSet **pset1, + AstPointSet **pset2, double *gx, double *gy, + double *dx, double *dy, int *flag, const char *method, + const char *class, int *status ){ +/* +* Name: +* GVec + +* Purpose: +* Returns a unit vector parallel to a physical axis at a given point. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int GVec( AstPlot *this, AstMapping *mapping, double *phy, +* int axis, double delta, AstPointSet **pset1, +* AstPointSet **pset2, double *gx, double *gy, +* double *dx, double *dy, int *flag, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function returns a unit vector (in the graphics coordinate +* system) in the positive direction of the specified physical axis, +* at the given physical position. It works by transforming the given +* physical position, together with another very close position, and +* returning the vector between them. It is possible for a +* discontinuity to occur between these two close positions, +* resulting in a very large meaningless vector prior to +* normalisation. For this reason two vectors are found, one joining +* the given position to a close position higher up the axis, and one +* joining a close position lower down the axis to the given position. +* If these two vectors differ in magnitude by a large factor, then +* the shorter of the two vectors is normalised and returned. +* Otherwise, the vector which is closest in direction to the vector +* supplied in [dx,dy] is returned. The returned vector is reversed if +* necessary so that it always points in the positive direction of the +* axis. +* +* If neither of the two vectors can be found (i.e. if the graphics +* coordinates are bad, or coincident), then the vector supplied in +* [dx,dy] is returned unchanged, and a function value of zero is +* returned. Otherwise, a function value of one is returned. + +* Parameters: +* this +* Pointer to the Plot. +* mapping +* Pointer to the Mapping from the base Frame of the Plot ot the +* current Frame. +* phy +* Pointer to an array holding the coordinates in the current Frame +* of the Plot at which the tangent vector is required. +* axis +* The index of the axis within the current Frame for which the +* tangent vector is required. +* delta +* The increment in the axis value to use between positions defining +* the vectors. +* pset1 +* A pointer to a place at which to store a pointer to a PointSet +* holding current Frame coordinates. This PointSet pointer should +* be supplied as NULL on the first call to this function, resulting +* in a new PointSet being created and a pointer to it returned. +* Subsequent calls to this function shopuld retain the pointer +* returned by the first call. The PointSet pointer should be +* annulled using astAnnul when no longer needed. +* pset2 +* A pointer to a place at which to store a pointer to a PointSet +* holding base Frame coordinates. This PointSet is managed in the +* same way as "pset1". +* gx +* A pointer to a double in which to return the graphics X +* coordinate of the position supplied by "phy". +* gy +* A pointer to a double in which to return the graphics Y +* coordinate of the position supplied by "phy". +* dx +* A pointer to a double in which to return the X component +* of the unit tangent vector. This should be supplied holding a +* "default" unit vector which is left unchanged if no new vector +* can be found. +* dy +* A pointer to a double in which to return the Y component +* of the unit tangent vector. This should be supplied holding a +* "default" unit vector which is left unchanged if no new vector +* can be found. +* flag +* A pointer to an int in which to return a flag indicating which +* of the two vectors was returned. Zero is returned if the vector +* was estimated by moving in a positive direction along the axis +* from the position supplied by "phy". One is returned if the vector +* was estimated by moving in a negative direction along the axis +* from the position supplied by "phy" (in this case the returned +* vector will have been negated so that it refers to the positive +* direction). +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* One is returned if the vector was found succesfully, Zero is returned +* if the vector could not be estimated for any reason. No error is +* reported if the failure was due to the nature of the mapping. + +* Notes: +* - If an error has already occurred, or if this function should fail +* for any reason, then a NULL pointer is returned. +*/ + +/* Local Variables: */ + double dd1; /* Length of positive vector */ + double dd2; /* Length of negative vector */ + double dx1; /* X component of positive vector */ + double dx2; /* X component of negative vector */ + double dy1; /* Y component of positive vector */ + double dy2; /* Y component of negative vector */ + double **ptr1; /* Pointers to physical coordinate data */ + double **ptr2; /* Pointers to graphics coordinate data */ + int i; /* Axis index */ + int nphy; /* No. of axes in current (physical) Frame */ + int ret; /* Was a vector estimated succesfully? */ + +/* Check the global status. */ + if( !astOK ) return 0; + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + dx1 = 0.0; + dx2 = 0.0; + dy1 = 0.0; + dy2 = 0.0; + +/* Initialise the returned value to indicate that the vector can not + be found. */ + ret = 0; + +/* Get the number of physical coordinates from the mapping. */ + nphy = astGetNout( mapping ); + +/* If no PointSets have been supplied, create some now. PointSet 1 + contains physical coordinates, PointSet 2 contains graphics + coordinates. */ + if( !(*pset1) ) *pset1 = astPointSet( 3, nphy, "", status ); + if( !(*pset2) ) *pset2 = astPointSet( 3, 2, "", status ); + +/* Get pointers to the PointSet data. */ + ptr1 = astGetPoints( *pset1 ); + ptr2 = astGetPoints( *pset2 ); + +/* Check the PointSets can be used. */ + if( astOK ){ + +/* Store the physical coordinates of three close points on a curve + parallel to the given axis, with the centre point at the given + position. */ + for( i = 0; i < nphy; i++ ){ + ptr1[ i ][ 0 ] = phy[ i ]; + ptr1[ i ][ 1 ] = phy[ i ]; + ptr1[ i ][ 2 ] = phy[ i ]; + } + + if( phy[ axis ] != AST__BAD ){ + ptr1[ axis ][ 0 ] = phy[ axis ] - delta; + ptr1[ axis ][ 2 ] = phy[ axis ] + delta; + } + +/* Find the corresponding graphics coordinates. */ + (void) Trans( this, NULL, mapping, *pset1, 0, *pset2, 0, method, class, status ); + +/* Check the central position is OK. */ + *gx = ptr2[ 0 ][ 1 ]; + *gy = ptr2[ 1 ][ 1 ]; + if( astOK && *gx != AST__BAD && *gy != AST__BAD ){ + +/* Get the unit vector between the central position and the position at + the higher physical axis value. Also get the length of the vector + joining the two positions. */ + if( ptr2[ 0 ][ 2 ] != AST__BAD && ptr2[ 1 ][ 2 ] != AST__BAD ){ + dx1 = ptr2[ 0 ][ 2 ] - *gx; + dy1 = ptr2[ 1 ][ 2 ] - *gy; + dd1 = dx1*dx1 + dy1*dy1; + + if( dd1 > 0.0 ) { + dd1 = sqrt( dd1 ); + dx1 /= dd1; + dy1 /= dd1; + } else { + dd1 = AST__BAD; + } + + } else { + dd1 = AST__BAD; + } + +/* Do the same for the position with lower physical axis value, + reversing the direction of the vector so that it refers to the + positive direction. */ + if( ptr2[ 0 ][ 0 ] != AST__BAD && ptr2[ 1 ][ 0 ] != AST__BAD ){ + dx2 = *gx - ptr2[ 0 ][ 0 ]; + dy2 = *gy - ptr2[ 1 ][ 0 ]; + dd2 = dx2*dx2 + dy2*dy2; + + if( dd2 > 0.0 ) { + dd2 = sqrt( dd2 ); + dx2 /= dd2; + dy2 /= dd2; + } else { + dd2 = AST__BAD; + } + + } else { + dd2 = AST__BAD; + } + +/* Only overwrite the supplied vector if at least one of the two tangent + vectors was defined. */ + if( dd1 != AST__BAD || dd2 != AST__BAD ){ + +/* If the first vector was not defined, return the second. */ + if( dd1 == AST__BAD ){ + *dx = dx2; + *dy = dy2; + *flag = 1; + ret = 1; + +/* If the second vector was not defined, return the first. */ + } else if( dd2 == AST__BAD ){ + *dx = dx1; + *dy = dy1; + *flag = 0; + ret = 1; + +/* If the first vector is much longer than the second, return the + second. */ + } else if( dd1 > 100.0*dd2 ){ + *dx = dx2; + *dy = dy2; + *flag = 1; + ret = 1; + +/* If the second vector is much longer than the first, return the + first. */ + } else if( dd2 > 100.0*dd1 ){ + *dx = dx1; + *dy = dy1; + *flag = 0; + ret = 1; + +/* If both vectors are defined and of comparable length, return the + vector which is most nearly parallel to the supplied vector. Note, we + assume that the supplied vector [dx,dy] is a unit vector. */ + } else if( *dx != AST__BAD && *dx != AST__BAD ){ + if( ( dx1*(*dx) + dy1*(*dy) )/dd1 > + ( dx2*(*dx) + dy2*(*dy) )/dd2 ){ + *dx = dx1; + *dy = dy1; + *flag = 0; + ret = 1; + + } else { + *dx = dx2; + *dy = dy2; + *flag = 1; + ret = 1; + } + +/* If no vector was supplied, return the shorter of the two vectors. */ + } else if( dd1 < dd2 ){ + *dx = dx1; + *dy = dy1; + *flag = 0; + ret = 1; + + } else { + *dx = dx2; + *dy = dy2; + *flag = 1; + ret = 1; + + } + + } + + } + + } + +/* Return the answer. */ + return ret; + +} + +static int HasEscapes( const char *text, int *status ) { +/* +* Name: +* HasEscapes + +* Purpose: +* Check if a text string contains any escape sequences. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int HasEscapes( const char *text, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function checks if a text string contains any escape sequences +* (see attribute Escape). + +* Parameters: +* text +* The text to check. +* status +* Pointer to the inherited status variable. + +* Returned: +* Non-zero if any escape sequences are found in the text. Zero +* otherwise. + +*/ + +/* Local Variables: */ + int result; + int type; + int value; + int nc; + +/* Initialise. */ + result = 0; + +/* Check the global error status and the supplied pointer. */ + if ( !astOK || ! text ) return result; + +/* Does the string begin with an escape sequence? */ + if( astFindEscape( text, &type, &value, &nc ) ){ + result = 1; + +/* If not, there must be an escape sequence later in the string if the + number of characters skipped by the above call to astFindEscape is less + than the length of the string. */ + } else if( nc < strlen( text ) ) { + result = 1; + } + +/* Return the result. */ + return result; +} + +static int IdFind( int id, int nax, int *id1, int *id2, int *id3, int *status ) { +/* +* Name: +* IdFind + +* Purpose: +* Find the numerical identifiers to use for a given identifier. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int IdFind( int id, int nax, int *id1, int *id2, int *id3, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* The supplied integer should be a numerical identifier for a +* graphical element of a plot (AST__MARKS_ID, AST__CURVES_ID, etc), or a +* "psuedo-identifier" which represents two other genuine identifiers. +* If the supplied value is a genuine identifier then it is returned +* in *id1, and *id2 is returned equal to -1. If the supplied value +* is a pseudo-identifier then the two corresponding genuine +* identifiers are returned in *id1 and *id2 + +* For instance, if "id" is AST__AXIS1_ID (a genuine id), then *id1 is +* returned equal to AST__AXIS1_ID and *id2 is returned equal to -1. If +* "id" is AST__AXES_ID (a pseudo-identifier), then *id1 is returned equal +* to AST__AXIS1_ID and *id2 is returned equal to AST__AXIS2_ID. + +* Genuine identifiers all have values which are less than the value +* of AST__NPID. Pseudo-identifiers have values which are greater than +* or equal to the value of AST__NPID. + +* Parameters: +* id +* The supplied identifier (genuine or pseudo). +* nax +* The number of axes spanning graphics space (2 or 3). +* id1 +* Pointer to the int at which to return the first genuine +* identifier corresponding to "id". +* id2 +* Pointer to the int at which to return the second genuine +* identifier corresponding to "id" (or -1 if "id" is a genuine +* identifier). +* id3 +* Pointer to the int at which to return the third genuine +* identifier corresponding to "id" (or -1 if "id" has no third +* genuine identifier). +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The number of genuine identifiers corresponding to the supplied +* (possibly Pseudo-) identifier. This will be in the range 1 to 3. + +*/ + +/* Local Variables: */ + int ret; + +/* Initialise returned values. */ + *id1 = id; + *id2 = -1; + *id3 = -1; + ret = 0; + +/* Check the local error status. */ + if ( !astOK ) return ret; + +/* Assume a genuine identifier was supplied. */ + ret = 1; + +/* Check against all known pseudo-identifier. */ + if( id == AST__AXES_ID ) { + ret = nax; + *id1 = AST__AXIS1_ID; + *id2 = AST__AXIS2_ID; + if( nax == 3 ) *id3 = AST__AXIS3_ID; + + } else if( id == AST__GRIDLINE_ID ) { + ret = nax; + *id1 = AST__GRIDLINE1_ID; + *id2 = AST__GRIDLINE2_ID; + if( nax == 3 ) *id3 = AST__GRIDLINE3_ID; + + } else if( id == AST__NUMLABS_ID ) { + ret = nax; + *id1 = AST__NUMLAB1_ID; + *id2 = AST__NUMLAB2_ID; + if( nax == 3 ) *id3 = AST__NUMLAB3_ID; + + } else if( id == AST__TEXTLABS_ID ) { + ret = nax; + *id1 = AST__TEXTLAB1_ID; + *id2 = AST__TEXTLAB2_ID; + if( nax == 3 ) *id3 = AST__TEXTLAB3_ID; + + } else if( id == AST__TICKS_ID ) { + ret = nax; + *id1 = AST__TICKS1_ID; + *id2 = AST__TICKS2_ID; + if( nax == 3 ) *id3 = AST__TICKS3_ID; + + } else if( id >= AST__NPID ) { + astError( AST__INTER, "AST internal programming error - " + "function IdFind in class Plot does not yet support " + "pseudo-identifier value %d", status, id ); + } + +/* Return the answer. */ + return ret; + +} + +void astInitPlotVtab_( AstPlotVtab *vtab, const char *name, int *status ) { +/* +*+ +* Name: +* astInitPlotVtab + +* Purpose: +* Initialise a virtual function table for a Plot. + +* Type: +* Protected function. + +* Synopsis: +* #include "plot.h" +* void astInitPlotVtab( AstPlotVtab *vtab, const char *name ) + +* Class Membership: +* Plot vtab initialiser. + +* Description: +* This function initialises the component of a virtual function +* table which is used by the Plot class. + +* Parameters: +* vtab +* Pointer to the virtual function table. The components used by +* all ancestral classes will be initialised if they have not already +* been initialised. +* name +* Pointer to a constant null-terminated character string which contains +* the name of the class to which the virtual function table belongs (it +* is this pointer value that will subsequently be returned by the Object +* astClass function). +*- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstFrameSetVtab *fset; /* Pointer to FrameSet component of Vtab */ + AstObjectVtab *object; /* Pointer to Object component of Vtab */ + AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ + +/* Check the local error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Initialize the component of the virtual function table used by the + parent class. */ + astInitFrameSetVtab( (AstFrameSetVtab *) vtab, name ); + +/* Store a unique "magic" value in the virtual function table. This will be + used (by astIsAPlot) to determine if an object belongs to this class. + We can conveniently use the address of the (static) class_init variable to + generate this unique value. */ + vtab->id.check = &class_check; + vtab->id.parent = &(((AstFrameSetVtab *) vtab)->id); + +/* Initialise member function pointers. */ +/* ------------------------------------ */ +/* Store pointers to the member functions (implemented here) that provide + virtual methods for this class. */ + vtab->BBuf = BBuf; + vtab->Border = Border; + vtab->BoundingBox = BoundingBox; + vtab->ClearGrid = ClearGrid; + vtab->ClearTol = ClearTol; + vtab->Clip = Clip; + vtab->CopyPlotDefaults = CopyPlotDefaults; + vtab->Curve = Curve; + vtab->CvBrk = CvBrk; + vtab->EBuf = EBuf; + vtab->GenCurve = GenCurve; + vtab->GetDrawnTicks = GetDrawnTicks; + vtab->GetGrid = GetGrid; + vtab->GetTol = GetTol; + vtab->GrfPop = GrfPop; + vtab->GrfPush = GrfPush; + vtab->GrfSet = GrfSet; + vtab->GrfWrapper = GrfWrapper; + vtab->Grid = Grid; + vtab->GridLine = GridLine; + vtab->Mark = Mark; + vtab->Mirror = Mirror; + vtab->PolyCurve = PolyCurve; + vtab->RegionOutline = RegionOutline; + vtab->SetGrid = SetGrid; + vtab->SetTickValues = SetTickValues; + vtab->SetTol = SetTol; + vtab->TestGrid = TestGrid; + vtab->TestTol = TestTol; + vtab->Text = Text; + + vtab->ClearTickAll = ClearTickAll; + vtab->SetTickAll = SetTickAll; + vtab->GetTickAll = GetTickAll; + vtab->TestTickAll = TestTickAll; + + vtab->ClearForceExterior = ClearForceExterior; + vtab->SetForceExterior = SetForceExterior; + vtab->GetForceExterior = GetForceExterior; + vtab->TestForceExterior = TestForceExterior; + + vtab->ClearInvisible = ClearInvisible; + vtab->SetInvisible = SetInvisible; + vtab->GetInvisible = GetInvisible; + vtab->TestInvisible = TestInvisible; + vtab->ClearBorder = ClearBorder; + vtab->SetBorder = SetBorder; + vtab->GetBorder = GetBorder; + vtab->TestBorder = TestBorder; + vtab->ClearInk = ClearInk; + vtab->SetInk = SetInk; + vtab->GetInk = GetInk; + vtab->TestInk = TestInk; + vtab->ClearClipOp = ClearClipOp; + vtab->SetClipOp = SetClipOp; + vtab->GetClipOp = GetClipOp; + vtab->TestClipOp = TestClipOp; + vtab->ClearClip = ClearClip; + vtab->SetClip = SetClip; + vtab->GetClip = GetClip; + vtab->TestClip = TestClip; + vtab->ClearGrf = ClearGrf; + vtab->SetGrf = SetGrf; + vtab->GetGrf = GetGrf; + vtab->TestGrf = TestGrf; + vtab->ClearDrawTitle = ClearDrawTitle; + vtab->SetDrawTitle = SetDrawTitle; + vtab->GetDrawTitle = GetDrawTitle; + vtab->TestDrawTitle = TestDrawTitle; + vtab->ClearLabelUp = ClearLabelUp; + vtab->SetLabelUp = SetLabelUp; + vtab->GetLabelUp = GetLabelUp; + vtab->TestLabelUp = TestLabelUp; + vtab->ClearLogPlot = ClearLogPlot; + vtab->SetLogPlot = SetLogPlot; + vtab->GetLogPlot = GetLogPlot; + vtab->TestLogPlot = TestLogPlot; + vtab->ClearLogTicks = ClearLogTicks; + vtab->SetLogTicks = SetLogTicks; + vtab->GetLogTicks = GetLogTicks; + vtab->TestLogTicks = TestLogTicks; + vtab->ClearLogLabel = ClearLogLabel; + vtab->SetLogLabel = SetLogLabel; + vtab->GetLogLabel = GetLogLabel; + vtab->TestLogLabel = TestLogLabel; + vtab->ClearDrawAxes = ClearDrawAxes; + vtab->SetDrawAxes = SetDrawAxes; + vtab->GetDrawAxes = GetDrawAxes; + vtab->TestDrawAxes = TestDrawAxes; + vtab->ClearAbbrev = ClearAbbrev; + vtab->SetAbbrev = SetAbbrev; + vtab->GetAbbrev = GetAbbrev; + vtab->TestAbbrev = TestAbbrev; + vtab->ClearEscape = ClearEscape; + vtab->SetEscape = SetEscape; + vtab->GetEscape = GetEscape; + vtab->TestEscape = TestEscape; + vtab->ClearLabelling = ClearLabelling; + vtab->SetLabelling = SetLabelling; + vtab->GetLabelling = GetLabelling; + vtab->TestLabelling = TestLabelling; + vtab->ClearMajTickLen = ClearMajTickLen; + vtab->SetMajTickLen = SetMajTickLen; + vtab->GetMajTickLen = GetMajTickLen; + vtab->TestMajTickLen = TestMajTickLen; + vtab->ClearLogGap = ClearLogGap; + vtab->SetLogGap = SetLogGap; + vtab->GetLogGap = GetLogGap; + vtab->TestLogGap = TestLogGap; + vtab->ClearTitleGap = ClearTitleGap; + vtab->SetTitleGap = SetTitleGap; + vtab->GetTitleGap = GetTitleGap; + vtab->TestTitleGap = TestTitleGap; + vtab->ClearMinTickLen = ClearMinTickLen; + vtab->SetMinTickLen = SetMinTickLen; + vtab->GetMinTickLen = GetMinTickLen; + vtab->TestMinTickLen = TestMinTickLen; + vtab->ClearNumLabGap = ClearNumLabGap; + vtab->SetNumLabGap = SetNumLabGap; + vtab->GetNumLabGap = GetNumLabGap; + vtab->TestNumLabGap = TestNumLabGap; + vtab->ClearTextLabGap = ClearTextLabGap; + vtab->SetTextLabGap = SetTextLabGap; + vtab->GetTextLabGap = GetTextLabGap; + vtab->TestTextLabGap = TestTextLabGap; + vtab->ClearLabelAt = ClearLabelAt; + vtab->SetLabelAt = SetLabelAt; + vtab->GetLabelAt = GetLabelAt; + vtab->TestLabelAt = TestLabelAt; + vtab->ClearCentre = ClearCentre; + vtab->SetCentre = SetCentre; + vtab->GetCentre = GetCentre; + vtab->TestCentre = TestCentre; + vtab->ClearGap = ClearGap; + vtab->SetGap = SetGap; + vtab->GetGap = GetGap; + vtab->TestGap = TestGap; + vtab->ClearEdge = ClearEdge; + vtab->SetEdge = SetEdge; + vtab->GetEdge = GetEdge; + vtab->TestEdge = TestEdge; + vtab->ClearNumLab = ClearNumLab; + vtab->SetNumLab = SetNumLab; + vtab->GetNumLab = GetNumLab; + vtab->TestNumLab = TestNumLab; + vtab->ClearMinTick = ClearMinTick; + vtab->SetMinTick = SetMinTick; + vtab->GetMinTick = GetMinTick; + vtab->TestMinTick = TestMinTick; + vtab->ClearTextLab = ClearTextLab; + vtab->SetTextLab = SetTextLab; + vtab->GetTextLab = GetTextLab; + vtab->TestTextLab = TestTextLab; + vtab->ClearLabelUnits = ClearLabelUnits; + vtab->SetLabelUnits = SetLabelUnits; + vtab->GetLabelUnits = GetLabelUnits; + vtab->TestLabelUnits = TestLabelUnits; + vtab->ClearStyle = ClearStyle; + vtab->SetStyle = SetStyle; + vtab->GetStyle = GetStyle; + vtab->TestStyle = TestStyle; + vtab->ClearFont = ClearFont; + vtab->SetFont = SetFont; + vtab->GetFont = GetFont; + vtab->TestFont = TestFont; + vtab->ClearColour = ClearColour; + vtab->SetColour = SetColour; + vtab->GetColour = GetColour; + vtab->TestColour = TestColour; + vtab->ClearWidth = ClearWidth; + vtab->SetWidth = SetWidth; + vtab->GetWidth = GetWidth; + vtab->TestWidth = TestWidth; + vtab->ClearSize = ClearSize; + vtab->SetSize = SetSize; + vtab->GetSize = GetSize; + vtab->TestSize = TestSize; + vtab->GetGrfContext = GetGrfContext; + +/* Save the inherited pointers to methods that will be extended, and replace + them with pointers to the new member functions. */ + object = (AstObjectVtab *) vtab; + mapping = (AstMappingVtab *) vtab; + fset = (AstFrameSetVtab *) vtab; + + parent_clearattrib = object->ClearAttrib; + object->ClearAttrib = ClearAttrib; + parent_getattrib = object->GetAttrib; + object->GetAttrib = GetAttrib; + parent_setattrib = object->SetAttrib; + object->SetAttrib = SetAttrib; + parent_testattrib = object->TestAttrib; + object->TestAttrib = TestAttrib; + +#if defined(THREAD_SAFE) + parent_managelock = object->ManageLock; + object->ManageLock = ManageLock; +#endif + + parent_transform = mapping->Transform; + mapping->Transform = Transform; + + parent_removeframe = fset->RemoveFrame; + fset->RemoveFrame = RemoveFrame; + +/* Declare the destructor and copy constructor. */ + astSetDelete( (AstObjectVtab *) vtab, Delete ); + astSetCopy( (AstObjectVtab *) vtab, Copy ); + +/* Declare the class dump function. */ + astSetDump( vtab, Dump, "Plot", "Provide facilities for 2D graphical output" ); + +/* If we have just initialised the vtab for the current class, indicate + that the vtab is now initialised, and store a pointer to the class + identifier in the base "object" level of the vtab. */ + if( vtab == &class_vtab ) { + class_init = 1; + astSetVtabClassIdentifier( vtab, &(vtab->id) ); + } +} + +static int Inside( int n, float *cx, float *cy, float x, float y, int *status ){ +/* +* Name: +* Inside + +* Purpose: +* See if a given point is inside a 2-d polygon. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int Inside( int n, float *cx, float *cy, float x, float y, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function determines if the position given by x and y, is inside +* or outside the polygon specified by the vertices given in arrays cx +* and cy. + +* Parameters: +* n +* The number of vertices in the polygon. +* cx +* A pointer to an array holding the x coordinates at the "n" vertices. +* cy +* A pointer to an array holding the y coordinates at the "n" vertices. +* x +* The x coordinate of the test point. +* y +* The y coordinate of the test point. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A boolean flag indicating if the test point is inside the polygon. + +* Notes: +* - The algorithm used only works for convex polygons. +* - The polygon is closed by joining the last vertex to the first +* vertex. +* - Zero is returned if an error has occurred. + +*/ + +/* Local Variables: */ + int i; /* Index of the current vertex */ + int j; /* Index of the next vertex */ + int ret; /* Is the test point inside the polygon? */ + int sgn; /* Which side of the first edge is the test point? */ + +/* Check the global status. */ + if( !astOK ) return 0; + +/* Initialise the returned value to indicate that the point is inside the + box. */ + ret = 1; + +/* Get the sign of the angle between the vector joining vertex 1 to vertex + 0, and the vector joining the test point to vertex zero. */ + if( ( cx[ 1 ] - cx[ 0 ] )*( y - cy[ 0 ] ) > + ( x - cx[ 0 ] )*( cy[ 1 ] - cy[ 0 ] ) ){ + sgn = 1; + } else { + sgn = -1; + } + +/* Check that the remaining test point is on the same side of the remaining + sides. */ + for( i = 1; i < n; i++ ){ + +/* Get the index of the next vertex, joining the last vertex up with + vertex zero. */ + j = i + 1; + if( j >= n ) j -= n; + +/* Get the sign of the angle between the vector joining vertex j to vertex + i, and the vector joining the test point to vertex i. If the sign is + opposite to that found for vertex zero, then the test point is outside + the polygon. Break out of the loop if this is the case. */ + if( ( cx[ j ] - cx[ i ] )*( y - cy[ i ] ) > + ( x - cx[ i ] )*( cy[ j ] - cy[ i ] ) ){ + + if( sgn == -1 ) { + ret = 0; + break; + } + + } else { + + if( sgn == 1 ) { + ret = 0; + break; + } + + } + + } + + +/* Return the answer. */ + return ret; + +} + +static void InterpEscape( AstPlot *this, int type, double value, float *x, + float *y, float ux, float uy, float rx, float ry, + const char *just, float *rise, double nsize, + double nstyle, double nwidth, double ncol, + double nfont, const char *method, const char *class, int *status ){ +/* +* Name: +* InterpEscape + +* Purpose: +* Prepare things for drawing the next part of a string which includes +* graphics escape sequences. + +* Synopsis: +* #include "plot.h" +* void InterpEscape( AstPlot *this, int type, double value, float *x, +* float *y, float ux, float uy, float rx, float ry, +* const char *just, float *rise, double nsize, +* double nstyle, double nwidth, double ncol, +* double nfont, const char *method, const char *class, int *status ) + +* Description: +* This function modifies the current graphics attributes, the supplied +* reference position, in preparation for drawing another sub-string +* from a string containing graphics escape sequences. The type and +* value of an escape sequence preceding the substring is supplied. +* Note, this function ignored escape sequences which represent an +* escaped percent sign. Such escape sequences are drawn as normal +* text by the claling function. + +* Parameters: +* this +* The plot. +* type +* The type of escape sequence. Each type is identified by a symbolic +* constant defined in grf.h. +* value +* The value associated with the escape sequence. All usable values +* will be positive. A value of -1 shold be supplied if the attribute +* identified by "type" should be reset to its "normal" value (as +* established using the astGAttr function, etc). +* x +* Pointer to a double holding the x coordinate at the concatenation +* point. This will be modified on exit if the escape sequence +* requires it. +* y +* Pointer to a double holding the y coordinate at the concatenation +* point. This will be modified on exit if the escape sequence +* requires it. +* ux +* The x component of the up-vector for the text, in graphics coords. +* The length of this vector should be equal to the height of normal +* text drawn with this up-vector. +* uy +* The y component of the up-vector for the text. See "ux". +* rx +* The x component of the right-vector for the text. The length of this +* vector should be equal to the height of normal text drawn with the +* supplied up-vector. +* ry +* The y component of the right-vector for the text. see "rx". +* just +* The justification being used for each substring. +* rise +* Pointer to a float holding the height of the current baseline +* above the normal baseline, given as a percentage of the height of +* normal text. May be negative for sub-scripts. May be modified on +* exit if the escape sequence effects the height of the baseline. +* nsize +* The size of normal text. +* nstyle +* The style of normal text. +* nwidth +* The width of normal text. +* ncol +* The colour of normal text. +* nfont +* The font of normal text. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + float new_rise; + float t1, t2; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Type GRF__ESSUP: Move the concatenation point in the up direction, and + update the current baseline height. If the value is -1, then reset the + baseline to its normal height. */ + if( type == GRF__ESSUP ) { + if( value > 0 ) { + *x += 0.01*ux*( value - *rise ); + *y += 0.01*uy*( value - *rise ); + *rise = value; + } else { + *x -= 0.01*ux*(*rise); + *y -= 0.01*uy*(*rise); + *rise = 0; + } + +/* Type GRF__ESSUB: Move the concatenation point in the down direction, and + update the current baseline height. If the value is -1, then reset the + baseline to its normal height. */ + } else if( type == GRF__ESSUB ) { + if( value > 0 ) { + *x -= 0.01*ux*( value + *rise ); + *y -= 0.01*uy*( value + *rise ); + *rise = -value; + } else { + *x -= 0.01*ux*(*rise); + *y -= 0.01*uy*(*rise); + *rise = 0; + } + +/* Type GRF__ESGAP: Move the concatenation point to the right. */ + } else if( type == GRF__ESGAP ) { + *x += 0.01*rx*value; + *y += 0.01*ry*value; + +/* Type GRF__ESBAC: Move the concatenation point to the left. */ + } else if( type == GRF__ESBAC ) { + *x -= 0.01*rx*value; + *y -= 0.01*ry*value; + +/* Remember the current horizontal position. */ + } else if( type == GRF__ESH ) { + this->hmarkx = *x; + this->hmarky = *y; + +/* Go to the previously stored horizontal position. */ + } else if( type == GRF__ESG ) { + if( this->hmarkx != FLT_MAX && this->hmarky != FLT_MAX ) { + t1 = ( *x - this->hmarkx )*rx + ( *y - this->hmarky )*ry; + t2 = rx*rx + ry*ry; + *x -= rx*t1/t2; + *y -= ry*t1/t2; + } + +/* Type GRF__ESSIZ: Change the text size. */ + } else if( type == GRF__ESSIZ ) { + if( value < 0 ) value = 100.0; + GAttr( this, GRF__SIZE, 0.01*value*nsize, NULL, GRF__TEXT, + method, class, status ); + +/* Type GRF__ESWID: Change the text width. */ + } else if( type == GRF__ESWID ) { + if( value < 0 ) value = 100.0; + GAttr( this, GRF__WIDTH, 0.01*value*nwidth, NULL, GRF__TEXT, + method, class, status ); + +/* Type GRF__ESFON: Change the text font. */ + } else if( type == GRF__ESFON ) { + if( value < 0 ) value = nfont; + GAttr( this, GRF__FONT, value, NULL, GRF__TEXT, method, class, status ); + +/* Type GRF__ESCOL: Change the text colour. */ + } else if( type == GRF__ESCOL ) { + if( value < 0 ) value = ncol; + GAttr( this, GRF__COLOUR, value, NULL, GRF__TEXT, method, class, status ); + +/* Type GRF__ESSTY: Change the text style. */ + } else if( type == GRF__ESSTY ) { + if( value < 0 ) value = nstyle; + GAttr( this, GRF__STYLE, value, NULL, GRF__TEXT, method, class, status ); + +/* Type GRF__ESPSH: Push current attributes onto a stack. */ + } else if( type == GRF__ESPSH ) { + PushGat( this, *rise, method, class, status ); + +/* Type GRF__ESSTY: Reset everything to normal. */ + } else if( type == GRF__ESPOP ) { + + if( !PopGat( this, &new_rise, method, class, status ) ) { + new_rise = 0.0; + GAttr( this, GRF__SIZE, nsize, NULL, GRF__TEXT, method, class, status ); + GAttr( this, GRF__WIDTH, nwidth, NULL, GRF__TEXT, method, class, status ); + GAttr( this, GRF__COLOUR, ncol, NULL, GRF__TEXT, method, class, status ); + GAttr( this, GRF__FONT, nfont, NULL, GRF__TEXT, method, class, status ); + GAttr( this, GRF__STYLE, nstyle, NULL, GRF__TEXT, method, class, status ); + } + + *x -= 0.01*ux*( *rise - new_rise ); + *y -= 0.01*uy*( *rise - new_rise ); + *rise = new_rise; + + } +} + +static int IsASkyAxis( AstFrame *frm, int axis, int *status ) { +/* +* Name: +* IsASkyAxis + +* Purpose: +* Checks if a specified axis of the supplied Frame is a SkyAxis. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int IsASkyAxis( AstFrame *frm, int axis, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function checks if if a specified axis of the supplied Frame is +* a SkyAxis. + +* Parameters: +* frm +* The Frame. +* axis +* The zero-based axis index. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A boolean flag indicating if the axis is a SkyAxis. + +*/ + +/* Local Variables: */ + int ret; + AstAxis *ax; + +/* initialise */ + ret = 0; + +/* Check the global status. */ + if( !astOK ) return ret; + +/* Extract the required axis from the Frame and test if it is a SkyAxis. + Then free the axis memory. */ + ax = astGetAxis( frm, axis ); + ret = astIsASkyAxis( ax ); + ax = astAnnul( ax ); + +/* Return the answer. */ + return ret; + +} + +static int IsASkyFrame( AstObject *obj, int *status ) { +/* +* Name: +* IsASkyFrame + +* Purpose: +* Checks if the supplied Object ca be treated as a SkyFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int IsASkyFrame( AstObject *obj, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function checks if the supplied Object is a SkyFrame or a +* FrameSet which has a SkyFrame as its current Frame. + +* Parameters: +* obj +* The object. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A boolean flag indicating if the Object can be treated as SkyFrame. + +*/ + +/* Local Variables: */ + int ret; + AstFrame *frm; + +/* initialise */ + ret = 0; + +/* Check the global status. */ + if( !astOK ) return ret; + +/* If the Object is a SkyFrame, return 1. */ + if( astIsASkyFrame( obj ) ) { + ret = 1; + +/* If the Object is a FrameSet, check its current Frame recursively, + using this method. */ + } else if( astIsAFrameSet( obj ) ) { + frm = astGetFrame( (AstFrameSet *) obj, AST__CURRENT ); + ret = IsASkyFrame( (AstObject *) frm, status ); + frm = astAnnul( frm ); + } + +/* Return the answer. */ + return ret; + +} + +static const char *JustMB( AstPlot *this, int esc, const char *text, float *x, + float *y, float upx, float upy, const char *just, + float uxu, float uyu, float rxu, float ryu, + float *x0, float *y0, const char *method, + const char *class, int *status ){ +/* +* Name: +* JustMB + +* Purpose: +* Modifies a "M" vertical reference point to be a "B" reference point, +* if necessary. + +* Synopsis: +* #include "plot.h" +* const char *JustMB( AstPlot *this, int esc, const char *text, float *x, +* float *y, float upx, float upy, const char *just, +* float uxu, float uyu, float rxu, float ryu, +* float *x0, float *y0, const char *method, +* const char *class, int *status ) + +* Description: +* This function is used to modify the reference point and justification +* of a string by converting the vertical "M" justification option (which +* indicates that the reference point refers to the bottom of the +* bounding box) into a corresponding "B" option (which indicates that +* the reference point refers to the text baseline). The reference +* point is modified accordingly. +* +* This is only done if the grf module does not support "M" +* justification. Otherwise, the supplied justification string and +* reference point coordinates are returned unchanged. + +* Parameters: +* this +* The plot. +* esc +* Should escape sequences be interpreted? They will be printed +* literally otherwise. +* text +* Pointer to a null-terminated character string to be displayed. +* x +* Pointer to a double holding the x coordinate at the reference +* point. This is modified on exit if the supplied "just" string +* indicates that the supplied value refers to the bottom of the +* bounding box, and the grf module does not support such +* justification. In this case, the returned value is a point on +* the baseline of the text which would result in the bottom of +* the bounding box being at the supplied position. +* y +* Pointer to a double holding the y coordinate at the reference +* point. This is modified on exit if the supplied "just" string +* indicates that the supplied value refers to the bottom of the +* bounding box, and the grf module does not support such +* justification. In this case, the returned value is a point on +* the baseline of the text which would result in the bottom of +* the bounding box being at the supplied position. +* upx +* The x component of the up-vector for the text. Positive values +* always refer to displacements from left to right on the screen, +* even if the graphics x axis increases in the opposite sense. +* upy +* The y component of the up-vector for the text. Positive values +* always refer to displacements from left to right on the screen, +* even if the graphics y axis increases in the opposite sense. +* just +* A character string which specifies the location within the +* text string which is to be placed at the reference position +* given by x and y. The first character may be 'T' for "top", +* 'C' for "centre", 'B' for "baseline" or "M" for "bottom", and +* specifies the vertical location of the reference position. Note, +* "baseline" corresponds to the base-line of normal text,and "M" +* corresponds to the bottom of the bounding box. Some characters +* (eg "y", "g", "p", etc) and sub-scripts descend below the base-line. +* The second character may be 'L' for "left", 'C' for "centre", or 'R' +* for "right", and specifies the horizontal location of the +* reference position. If the string has less than 2 characters +* then 'C' is used for the missing characters. +* uxu +* X component of normalised up-vector, in graphics coords. +* uyu +* Y component of normalised up-vector, in graphics coords. +* rxu +* X component of normalised right-vector, in graphics coords. +* ryu +* Y component of normalised right-vector, in graphics coords. +* x0 +* Address of a float at which to return the x coordinate at the +* left end of the baseline of the whole string. +* y0 +* Address of a float at which to return the y coordinate at the +* left end of the baseline of the whole string. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to a dynamically allocated string which contains the +* justification to use in future. This pointer should be freed using +* astFree when no longer needed. This string will contain a full +* upper-case justification string which can be used by the current +* grf module. + +* Notes; +* - NULL is returned if an error has occurred. + +*/ + +/* Local Variables: */ + char cc; + float drop; + float dx; + float dy; + float f; + float height; + float width; + float xbn[ 4 ]; + float ybn[ 4 ]; + int called; + char *result; + +/* Check inherited status */ + if( !astOK ) return NULL; + +/* Allocate memory for the returned string. */ + result = astMalloc( sizeof( char )*3 ); + if( astOK ) { + +/* Fill in any missing parts of the justification string. */ + if( just ){ + cc = toupper( just[ 0 ] ); + result[ 0 ] = ( cc == 'T' || cc == 'C' || cc == 'B' || cc == 'M' ) ? cc : 'C'; + + cc = toupper( just[ 1 ] ); + result[ 1 ] = ( cc == 'L' || cc == 'C' || cc == 'R' ) ? cc : 'C'; + + } else { + result[ 0 ] = 'C'; + result[ 1 ] = 'C'; + } + + result[ 2 ] = 0; + +/* Indicate that DrawText has not been called. */ + called = 0; + +/* The justfication need not be changed unless the requested vertical + justification is "bottom" (m), AND the grf module does not support "M" + justification. */ + if( ( result[ 0 ] == 'M' ) && !GCap( this, GRF__MJUST, 1, status ) ){ + +/* Find the bounding box which would result from putting the left end of + the baseline at the specified position. */ + DrawText( this, 0, esc, text, *x, *y, "BL", upx, upy, xbn, ybn, + &drop, method, class, status ); + +/* Indicate that DrawText has not been called. */ + called = 1; + +/* Get the vector from the bottom left corner of the bounding box to the + reference point (on the base-line), and add this vector on to the reference + point. */ + *x += *x - xbn[ 0 ]; + *y += *y - ybn[ 0 ]; + +/* Modified the returned justification string. */ + result[ 0 ] = 'B'; + } + +/* If the returned justification is "BL", then the left end of the + baseline is just the returned reference point. */ + if( result[ 0 ] == 'B' && result[ 1 ] == 'L' ) { + *x0 = *x; + *y0 = *y; + +/* Otherwise, we work out the coords of the left end of the baseline from + the values returned by DrawText above. Call DrawText now if it was not + called above. */ + } else { + if( ! called ) { + DrawText( this, 0, esc, text, *x, *y, "BL", upx, upy, xbn, ybn, + &drop, method, class, status ); + } + +/* Find the height and width of the bounding box. */ + dx = xbn[ 0 ] - xbn[ 3 ]; + dy = ybn[ 0 ] - ybn[ 3 ]; + width = sqrt( dx*dx + dy*dy ); + + dx = xbn[ 0 ] - xbn[ 1 ]; + dy = ybn[ 0 ] - ybn[ 1 ]; + height = sqrt( dx*dx + dy*dy ); + +/* For "C" and "R" horizontal justification we first need to move the + returned reference point left by 0.5 or 1.0 times the width of the whole + string respectively. */ + if( result[ 1 ] == 'C' ) { + f = 0.5; + + } else if( result[ 1 ] == 'R' ) { + f = 1.0; + + } else { + f = 0.0; + } + + f *= width; + + *x0 = *x - f*rxu; + *y0 = *y - f*ryu; + +/* Unless the vertical justification is "B", we also need to move the + concatenation point vertically to put it on the baseline. */ + if( result[ 0 ] == 'T' ) { + f = height - drop; + + } else if( result[ 0 ] == 'C' ) { + f = 0.5*height - drop; + + } else if( result[ 0 ] == 'M' ) { + f = -drop; + + } else { + f = 0.0; + } + + *x0 -= f*uxu; + *y0 -= f*uyu; + } + } + +/* Return the result. */ + return result; +} + +static int Labelat( AstPlot *this, TickInfo **grid, AstPlotCurveData **cdata, + double *labelat, const char *method, const char *class, + int *status ){ +/* +* +* Name: +* Labelat + +* Purpose: +* Determine the other axis value at which to place interior labels +* and tick marks. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int Labelat( AstPlot *this, TickInfo **grid, AstPlotCurveData **cdata, +* double *labelat, const char *method, const char *class ) + +* Class Membership: +* Plot member function. + +* Description: +* If tick marks and labels are to be placed within the plotting area, +* the tick values stored in "grid" determine their position on one +* axis, and their position on the other axis is determined by this +* function. If a value has been set for the "LabelAt" attribute, then +* it is used, otherwise the "other axis" value on the longest curve +* parallel to the "other axis" is used (although the curve "other axis +* = zero" is used if it passes through the plotting area and is not too +* short). The effective length assigned to each curve is reduced in +* proportion to the number of tick marks which are close to the edge +* of the plotting area. +* +* A flag is returned indicating if the two axes appear to be +* independent, in which case there is nothing to be gained by using +* interior labelling. + +* Parameters: +* this +* A pointer to the Plot. +* grid +* A pointer to an array of two TickInfo pointers (one for each axis), +* each pointing to a TickInfo structure holding information about +* tick values on the axis. See function GridLines. +* cdata +* A pointer to an array of two AstPlotCurveData pointers (one for each axis), +* each pointing to an array of AstPlotCurveData structure (one for each +* major tick value on the axis), holding information about breaks +* in the curves drawn to mark the major tick values. See function +* DrawGrid. +* labelat +* A pointer to a 2 element array in which to store the constant axis +* values at which tick marks are put. Element 0 is returned holding +* the axis 1 value at which tick marks for axis 0 are placed. Element +* 1 is returned holding the axis 0 value at which tick marks for axis +* 1 are placed. +* flags +* A pointer to a 2 element array. Each element is a flag which is +* returned non-zero if the corresponding axis +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. + +* Returned Value: +* Zero if and only if the lines of constant axis value are all the +* same length for all tick marks on either axis. If this is so, using +* interior labelling will not enable any more major ticks to be +* drawn, and so there is no reason to switch to interior labelling (unless +* the user has specifically requested interior labelling). + +* Notes: +* - This function assumes the current Frame of the Plot is 2 +* dimensional, and it should not be called if this is not the case. +*/ + +/* Local Variables: */ + AstMapping *mapping; /* Mapping from graphics to physical coords */ + AstPointSet *pset2; /* Pointset for graphical tick positions */ + AstPointSet *pset[ 2 ];/* Pointsets for physical tick positions */ + AstPlotCurveData *cdt; /* Pointer to the AstPlotCurveData for the next tick */ + TickInfo *info; /* Pointer to the TickInfo for the current axis */ + double **ptr2; /* Pointers to graphics pointset data */ + double *ptr1[ 2 ]; /* Pointers to physical pointset data */ + double *tvals[ 2 ]; /* Pointers to arrays of other axis values */ + double *value; /* Current tick value */ + double efflen; /* Effective length of current curve */ + double lim; /* Largest insignificant axis value */ + double margin; /* Width of margin around plotting area */ + double maxlen; /* Effective length of longest curve */ + double minlen; /* Effective length of shortest (non-zero) curve */ + double x; /* Tick X value */ + double xhi; /* Upper limit on acceptable X range */ + double xlo; /* Lower limit on acceptable X range */ + double y; /* Tick Y value */ + double yhi; /* Upper limit on acceptable Y range */ + double ylo; /* Lower limit on acceptable Y range */ + double zerolen; /* Effective length of curve for other axis = 0.0 */ + int axis; /* Current axis index */ + int i; /* Tick index for this axis */ + int nin; /* No. of counted ticks */ + int result; /* Does interior labelling allow more ticks to be drawn? */ + int tick; /* Tick index */ + +/* Check the global status. */ + if( !astOK ) return 0; + +/* Initialise */ + result = 1; + +/* Create two PointSets to hold a set of tick mark positions along each + axis. The values on "axis" will be taken from the info structure. For + each axis create an array to hold values for the "other" axis. */ + for( axis = 0; axis < 2; axis++ ){ + info = grid[ axis ]; + pset[ axis ] = astPointSet( info->nmajor, 2, "", status ); + tvals[ axis ] = (double *) astMalloc( sizeof(double)*(size_t)(info->nmajor) ); + } + +/* Get the mapping from Base (graphics) frame the Current (physical) */ + mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); + +/* Get the bounds of the area in which tick marks must occur to be + counted. This is the total plotting area minus a 5% margin at each + edge. */ + margin = 0.05*( this->xhi - this->xlo ); + xlo = this->xlo + margin; + xhi = this->xhi - margin; + + margin = 0.05*( this->yhi - this->ylo ); + ylo = this->ylo + margin; + yhi = this->yhi - margin; + +/* Do each axis. */ + for( axis = 0; axis < 2 && astOK; axis++ ){ + +/* Find the longest and shortest curves parallel to the axis being labelled. + Also find the length of the curve which passes through the origin of the + other axis which is within the plotting area. We need to do this even + if LabelAt has been set since we need to calculate the returned flag. */ + +/* Store pointers to the arrays holding tick mark physical coordinates, + and set these in the PointSet. */ + ptr1[ axis ] = grid[ axis ]->ticks; + ptr1[ 1 - axis ] = tvals[ axis ]; + astSetPoints( pset[ axis ], ptr1 ); + +/* Get a pointer to the structure containing information describing the + positions of the major tick marks along the other axis. */ + info = grid[ 1 - axis ]; + +/* Get a pointer to the other axis value at the first other axis major tick + mark. */ + value = info->ticks; + +/* Get a limit on absolute magnitude for an axis value to be consider + equal to zero. */ + lim = 1.0E-6*fabs( value[ 1 ] - value [ 0 ] ); + +/* Get a pointer to the structure containing information describing the + breaks in the curve which passes through the first major tick mark. */ + cdt = cdata[ 1 - axis ]; + +/* Initialise the effective length of the longest and shortest curves, and + the curve passing through the origin. */ + maxlen = -1.0; + minlen = DBL_MAX; + zerolen = 0.0; + labelat[ axis ] = AST__BAD; + +/* Loop round each of the major tick marks on the other axis. */ + for( tick = 0; tick < info->nmajor && astOK; tick++ ){ + +/* Fill the array of other axis values with the current other axis value. */ + for( i = 0; i < grid[ axis ]->nmajor; i++ ){ + tvals[ axis ][ i ] = *value; + } + +/* Transform the tick positions from the current frame (i.e. physical + coordinates) to the base frame (i.e. graphics coordinates) using + the inverse Mapping. */ + pset2 = Trans( this, NULL, mapping, pset[ axis ], 0, NULL, 0, + method, class, status ); + +/* Get pointers to the graphics coordinates. */ + ptr2 = astGetPoints( pset2 ); + if( astOK ) { + +/* Count the number of graphics positions which are well within the plotting + area. */ + nin = 0; + for( i = 0; i < grid[ axis ]->nmajor; i++ ){ + x = ptr2[ 0 ][ i ]; + y = ptr2[ 1 ][ i ]; + if( x != AST__BAD && x > xlo && x < xhi && + y != AST__BAD && y > ylo && y < yhi ) nin++; + } + +/* Find the effective length of this curve.*/ + efflen = sqrt( (float) nin )*cdt->length; + +/* If the curve through this tick mark has a greater effective length than any + other found so far, record it. */ + if( efflen > maxlen ){ + maxlen = efflen; + labelat[ axis ] = *value; + } + +/* If the curve through this tick mark has a smaller non-zero effective length + than any other found so far, record it. */ + if( efflen < minlen && efflen > 0.0 ) minlen = efflen; + +/* If this tick mark is at the origin, note the effective length. */ + if( fabs( *value ) <= lim ) zerolen = efflen; + +/* Get a pointer to the curve through the next major tick mark. */ + cdt++; + +/* Get a pointer to the axis value at the next major tick mark. */ + value++; + + } + +/* Free resources. */ + pset2 = astAnnul( pset2 ); + } + +/* Use the curve through the origin unless it is significantly shorter + than the longest curve. */ + if( zerolen > 0.4*maxlen ) labelat[ axis ] = 0.0; + +/* Return a flag if the lengths of the shortest and longest curves are nearly + equal. */ + if( ( maxlen - minlen )/( maxlen + minlen ) < 1.0E-5 ) result = 0; + +/* If the LabelAt attribute has been set, use it in preference to the + value found above. */ + if( astTestLabelAt( this, axis ) ){ + labelat[ axis ] = astGetLabelAt( this, axis ); + } + } + +/* Release resources. */ + for( axis = 0; axis < 2; axis++ ){ + if( pset[ axis ] ) pset[ axis ] = astAnnul( pset[ axis ] ); + if( tvals[ axis ] ) tvals[ axis ] = (double *) astFree( (void *) tvals[ axis ] ); + } + mapping = astAnnul( mapping ); + +/* Return. */ + return result; + +} + +static void Labels( AstPlot *this, TickInfo **grid, AstPlotCurveData **cdata, + double *gap, double *labelat, const char *method, + const char *class, int *status ){ +/* +* +* Name: +* Labels + +* Purpose: +* Draw numerical axis labels for a 2-D annotated coordinate grid. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Labels( AstPlot *this, TickInfo **grid, AstPlotCurveData **cdata, +* double *gap, double *labelat, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* The policy for placing labels for the major tick values is broadly as +* follows: if possible, labels for a given physical axis are placed on +* one edge of the plotting area, at the place where the curve for a +* major tick value crosses the edge. If very few of the curves cross +* the edge, then the label for a curve is placed at the intersection +* of that curve with the longest of the curves representing the major +* tick values on the other axis. + +* Parameters: +* this +* A pointer to the Plot. +* grid +* A pointer to an array of two TickInfo pointers (one for each axis), +* each pointing to a TickInfo structure holding information about +* tick values on the axis. See function GridLines. +* cdata +* A pointer to an array of two AstPlotCurveData pointers (one for each axis), +* each pointing to an array of AstPlotCurveData structure (one for each +* major tick value on the axis), holding information about breaks +* in the curves drawn to mark the major tick values. See function +* DrawGrid. +* gap +* Pointer to array of two values holding the gap between major +* tick values on the two axes. +* labelat +* A pointer to a 2 element array holding the constant axis +* values at which tick marks are put. Element 0 should hold +* the axis 1 value at which tick marks for axis 0 are placed. Element +* 1 should hold the axis 0 value at which tick marks for axis +* 1 are placed. If labels are to be placed round the edges of the +* plotting zone instead of within the plotting zone, then values of +* AST__BAD should be supplied. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Notes: +* - This function assumes the current Frame of the Plot is 2 +* dimensional, and it should not be called if this is not the case. +*/ + +/* Local Variables: */ + AstFrame *frame; /* Pointer to current Frame */ + AstMapping *mapping; /* Pointer to graphics->physical Mapping */ + AstPointSet *pset1; /* Pointer to PointSet holding physical coords. */ + AstPointSet *pset2; /* Pointer to PointSet holding graphics coords. */ + AstPlotCurveData *cdt; /* Pointer to the AstPlotCurveData for the next tick */ + LabelList *labellist; /* Pointer to list of labels to be plotted */ + LabelList *ll; /* Pointer to next label to be plotted */ + TickInfo *info; /* Pointer to the TickInfo for the current axis */ + char just_buf[3]; /* Buffer to hold a justification string */ + const char *just; /* Justification string */ + const char *text; /* Pointer to label text */ + double *used; /* Pointer to list of used label values */ + double *value; /* Current tick value */ + double diff; /* Difference between adjacent major tick marks */ + double dx; /* Text base-line X component */ + double dy; /* Text base-line Y component */ + double gx; /* Reference position graphics X coord. */ + double gy; /* Reference position graphics Y coord. */ + double mindim; /* Shortest dimension of plotting area */ + double offx; /* X component of offset vector */ + double offy; /* Y component of offset vector */ + double rlen; /* Length of perpendicular vector */ + double rx; /* X comp of vector perpendicular to (dx,dy) */ + double ry; /* Y comp of vector perpendicular to (dx,dy) */ + double sin45; /* Sine of 45 degrees */ + double txtgap; /* Absolute gap between labels and edges */ + double upx; /* Text up-vector X component */ + double upy; /* Text up-vector Y component */ + double val[ 2 ]; /* Physical coordinates */ + float *box; /* Pointer to array of label bounding boxes */ + float alpha; /* Factor to convert graphics X to equal scaled X */ + float beta; /* Factor to convert graphics Y to equal scaled Y */ + int axis; /* Current axis index */ + int esc; /* Interpret escape sequences? */ + int flag; /* Flag indicating which way the base-vector points */ + int iused; /* Index into list of used axis values */ + int last; /* The index of the last tick to use */ + int logticks; /* ARe major ticks spaced logarithmically? */ + int nlab; /* The number of labels to be plotted */ + int nused; /* Number of used axis values */ + int t0; /* Index of central tick */ + int tick; /* Current tick index */ + int tinc; /* Increment between ticks */ + int upfree; /* Are we free to change the up-vector? */ + int gelid; /* ID for next graphical element to be drawn */ + +/* Check the global status. */ + if( !astOK ) return; + +/* See if escape sequences in text strings are to be interpreted */ + esc = astGetEscape( this ); + +/* Empty the list of bounding boxes kept by the Overlap function. */ + (void) Overlap( this, 0, 0, NULL, 0.0, 0.0, NULL, 0.0, 0.0, NULL, + method, class, status ); + +/* If required, draw the labels around the edges of the plotting area. */ + if( labelat[ 0 ] == AST__BAD || labelat[ 1 ] == AST__BAD ){ + (void) EdgeLabels( this, 1, grid, cdata, 1, method, class, status ); + +/* Otherwise, draw labels within the interior of the plotting area. */ + } else { + +/* Find the scale factors for the two axes which scale graphics coordinates + into a "standard" equal scaled coordinate system in which: 1) the axes + have equal scale in terms of (for instance) millimetres per unit distance, + 2) X values increase from left to right, 3) Y values increase from bottom + to top. */ + GScales( this, &alpha, &beta, method, class, status ); + +/* Get the minimum dimension of the plotting area in equal scaled coords. */ + mindim = astMIN( fabs( alpha*(this->xhi - this->xlo) ), + fabs( beta*(this->yhi - this->ylo) ) ); + +/* Store a value for the sine of 45 degrees. */ + sin45 = 1.0/sqrt( 2.0 ); + +/* Initialise the pointer to the memory holding the bounding boxes for + all labels (used by function Overlap). */ + box = NULL; + +/* Get a pointer to the current Frame in the Plot. */ + frame = astGetFrame( this, AST__CURRENT ); + +/* Get a pointer to the mapping form the base Frame to the current Frame in + the Plot. */ + mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); + +/* Initialize the id value for graphical element being drawn. */ + gelid = AST__NUMLAB1_ID; + +/* Do each axis. */ + for( axis = 0; axis < 2; axis++ ){ + +/* See of major ticks are spaced logarithmically on this axis. */ + logticks = astGetLogTicks( this, axis ); + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + astGrfAttrs( this, gelid, 1, GRF__TEXT, method, class ); + +/* Get a pointer to the structure containing information describing the + positions of the major tick marks along this axis. */ + info = grid[ axis ]; + +/* Only progress if there are some labels stored within the structure. */ + if( info->labels ) { + +/* Initialise the pointer to the list of text strings to be drawn. */ + labellist = NULL; + nlab = 0; + +/* See if numerical labels are always to be drawn horizontal. If so, set + a flag and initialise a vertical up-vector. */ + if( astGetLabelUp( this, axis ) ){ + upfree = 0; + upx = 0.0; + upy = 1.0; + +/* Otherwise, clear the flag and indicate that we do not yet have an + up-vector. */ + } else { + upfree = 1; + upx = AST__BAD; + upy = AST__BAD; + } + +/* Indicate that the tangent vector to the other axis is not yet + known. */ + dx = AST__BAD; + dy = AST__BAD; + gx = AST__BAD; + gy = AST__BAD; + +/* Store the gap to put next to the label text. This is in equal scaled + coords, not graphics coords. */ + txtgap = astGetNumLabGap( this, axis )*mindim; + +/* Get a pointer to the structure containing information describing the + breaks in the curve which passes through the first major tick mark. */ + cdt = cdata[ axis ]; + +/* Get a pointer to the axis value at the first major tick mark. */ + value = info->ticks; + +/* Initialise pointers to two PointSets which will be created and used + within function GVec. */ + pset1 = NULL; + pset2 = NULL; + +/* Get memory to hold the axis values at which labels have been put. */ + used = (double *) astMalloc( sizeof(double)*(size_t)info->nmajor ); + nused = 0; + +/* The tick marks are done in two batches, each batch working out from the + middle. This is done because there may be extra tick marks outside the + normal ranges at the extremes, and these should not be given the + priority caused by doing them first. Store the mid-tick index, the + current tick index, and the increment between ticks. The ticks from the + middle up to the highest index are done first. */ + t0 = info->nmajor/2; + tick = t0 - 1; + tinc = 1; + +/* Loop round until all ticks have been done. */ + last = info->nmajor - 1; + while( (tick += tinc) >= 0 && astOK ){ + +/* If we have done the highest tick index, start again at the tick just + below middle, and work done towards index zero. */ + if( tick == info->nmajor ){ + tick = t0 - 1; + tinc = -1; + } + +/* Store the reference position for the label . */ + val[ axis ] = value[ tick ]; + val[ 1 - axis ] = labelat[ axis ]; + +/* Store the difference between this tick and the next. */ + if( logticks ) { + diff = value[ tick ]*( gap[ axis ] - 1.0 ); + } else { + diff = gap[ axis ]; + } + +/* See if this axis value has already been used. */ + for( iused = 0; iused < nused; iused++ ){ + if( fabs( val[ axis ] - used[ iused ] ) < + 1.0E-3*diff ) break; + } + +/* If the axis value has already been used, don't use it again. */ + if( iused >= nused || nused == 0 ){ + used[ nused++ ] = val[ axis ]; + +/* We now need to decide where to put the reference point for the text + string, and what justification to use. Assuming that NumLabGap is +ve, + the labels are drawn on the left hand side of the axis as seen by + someone moving along the axis in the positive direction, with an + up-vector which is normal to the axis tangent. First, find the graphics + coordinates at the point being labelled, and the unit tangent-vector + parallel to the axis being labelled. If the tangent vector is not defined, + then the tangent vector used for the previous label is re-used. This + unit tangent vector is expressed in graphics coords. */ + GVec( this, mapping, val, axis, 0.01*diff, &pset1, + &pset2, &gx, &gy, &dx, &dy, &flag, method, class, + status ); + +/* If we now have a tangent vector and good graphics coordinates for the + label's reference position... */ + if( dx != AST__BAD && dy != AST__BAD && + gx != AST__BAD && gy != AST__BAD ){ + +/* Convert the unit tangent vector from graphics coords to equal-scaled coords. */ + dx *= alpha; + dy *= beta; + +/* Rotate through 90 degrees to get a vector perpendicular to the axis in + equal scaled coords. This vector points to the left as you move along + the physical axis in the positive direction. Find its length. */ + rx = -dy; + ry = dx; + rlen = sqrt( rx*rx + ry*ry ); + +/* The reference position for the text is displaced away from the + reference position normal to the axis on the left hand side by the + "txtgap" value. */ + offx = rx*txtgap/rlen; + offy = ry*txtgap/rlen; + gx += offx/alpha; + gy += offy/beta; + +/* The up-vector and justification for the text depends on whether or + not the up-vector is free to rotate. If it is free, the up-vector is + chosen so that the text is not upside-down. Note, the up-vector is + specified in the equally scaled coordinate system. */ + if( upfree ){ + + if( dx < -0.01*fabs( alpha ) ){ + upx = -rx; + upy = -ry; + just = ( txtgap < 0.0 )? "BC" : "TC"; + } else { + upx = rx; + upy = ry; + just = ( txtgap < 0.0 )? "TC" : "BC"; + } + if( txtgap == 0.0 ) just = "CC"; + +/* If the up vector is required to be vertical, a system is used which + tries to put the centre of the text string on or near the offset + vector. */ + } else { + upx = 0.0; + upy = 1.0; + + if( offy > fabs(txtgap)*sin45 ){ + just_buf[0] = 'B'; + } else if( offy < -fabs(txtgap)*sin45 ){ + just_buf[0] = 'T'; + } else { + just_buf[0] = 'C'; + } + if( txtgap == 0.0 ) just_buf[0] = 'C'; + + if( offx < -fabs(txtgap)*sin45 ){ + just_buf[1] = 'R'; + } else if( offx > fabs(txtgap)*sin45 ){ + just_buf[1] = 'L'; + } else { + just_buf[1] = 'C'; + } + if( txtgap == 0.0 ) just_buf[1] = 'C'; + + just_buf[2] = 0; + just = just_buf; + } + +/* Get the label text. */ + text = (info->labels)[ tick ]; + if( text ){ + +/* Check that the reference position is within the plotting area. + If so, add it to the list of labels to be drawn. */ + if( gx >= this->xlo && gx <= this->xhi && + gy >= this->ylo && gy <= this->yhi ){ + + labellist = (LabelList *) astGrow( (void *) labellist, nlab + 1, sizeof(LabelList) ); + if ( astOK ) { + (labellist + nlab)->index = tick; + (labellist + nlab)->text = (char *) astStore( NULL, (void *) text, strlen(text) + 1 ); + (labellist + nlab)->x = gx; + (labellist + nlab)->y = gy; + (labellist + nlab)->just = (char *) astStore( NULL, (void *) just, strlen(just) + 1 ); + (labellist + nlab)->upx = upx; + (labellist + nlab)->upy = upy; + (labellist + nlab)->val = val[ axis ]; + nlab++; + } else { + break; + } + } + } + } + } + } + +/* If any labels were stored, draw the text strings, and then release the + memory used to hold the text, etc. */ + if( nlab > 0 ) { + PlotLabels( this, esc, frame, axis, labellist, info->fmt, nlab, + &box, method, class, status ); + ll = labellist; + for( tick = 0; tick < nlab; tick ++ ) { + ll->text = (char *) astFree( (void *) ll->text ); + ll->just = (char *) astFree( (void *) ll->just ); + ll++; + } + labellist = (LabelList *) astFree( (void *) labellist ); + } + +/* Free the memory used to hold the axis values at which labels have + been put. */ + used = (double *) astFree( (void *) used ); + +/* Annul the PointSets (if used). */ + if( pset1 ) pset1 = astAnnul( pset1 ); + if( pset2 ) pset2 = astAnnul( pset2 ); + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, gelid, 0, GRF__TEXT, method, class ); + +/* Set up the id for the next graphical element to be drawn. */ + gelid = AST__NUMLAB2_ID; + + } + } + +/* Free the memory used to hold the bounding boxes. */ + box = (float *) astFree( (void *) box ); + +/* Annul the pointers to the Frame and the Mapping. */ + mapping = astAnnul( mapping ); + frame = astAnnul( frame ); + + } + +/* Return. */ + return; + +} + +static void LinePlot( AstPlot *this, double xa, double ya, double xb, + double yb, int ink, AstPlotCurveData *cdata, + const char *method, const char *class, int *status ){ +/* +* +* Name: +* LinePlot + +* Purpose: +* Draws a straight line omitting bad regions. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void LinePlot( AstPlot *this, double xa, double ya, double xb, +* double yb, int ink, AstPlotCurveData *cdata, +* const char *method, const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function draws a straight line between two positions in graphics +* coordinates but leaves gaps in the line where it passes through +* regions which have no corresponding physical coordinates. + +* Parameters: +* this +* Pointer to the Plot. +* xa +* The graphics X coordinate at the start of the line. +* ya +* The graphics Y coordinate at the start of the line. +* xb +* The graphics X coordinate at the end of the line. +* yb +* The graphics Y coordinate at the end of the line. +* ink +* If zero, the line is not actually drawn, but information about +* the breaks is still returned. If non-zero, the line is also drawn. +* cdata +* A pointer to a structure in which to return information about the +* breaks in the line. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Notes: +* - No curve is draw if any of the start or end positions are bad +* (i.e. equal to AST__BAD), or if a NULL pointer is supplied for "cdata". +* No errors are reported in these cases. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + double d[ CRV_NPNT ]; /* Offsets to evenly spaced points along curve */ + double x[ CRV_NPNT ]; /* X coords at evenly spaced points along curve */ + double y[ CRV_NPNT ]; /* Y coords at evenly spaced points along curve */ + double tol; /* Absolute tolerance value */ + int i; /* Loop count */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Check the supplied values are usable. */ + if( xa == AST__BAD || ya == AST__BAD || + xb == AST__BAD || yb == AST__BAD || + !cdata ) return; + +/* Convert the tolerance from relative to absolute graphics coordinates. */ + tol = astGetTol( this )*astMAX( this->xhi - this->xlo, this->yhi - this->ylo ); + +/* Ensure the globals holding the scaling from graphics coords to equally + scaled coords are available. */ + GScales( this, NULL, NULL, method, class, status ); + +/* Set up the external variables used by the Crv and CrvLine function (see + their prologues for details). */ + Crv_scerr = ( astGetLogPlot( this, 0 ) || + astGetLogPlot( this, 1 ) ) ? 100.0 : 1.5; + Crv_ux0 = AST__BAD; + Crv_limit = 0.5*tol*tol; + Crv_tol = tol; + Crv_map = Map2; + Crv_ink = ink; + Crv_len = 0.0F; + Crv_xlo = this->xlo; + Crv_xhi = this->xhi; + Crv_ylo = this->ylo; + Crv_yhi = this->yhi; + Crv_out = 1; + Crv_xbrk = cdata->xbrk; + Crv_ybrk = cdata->ybrk; + Crv_vxbrk = cdata->vxbrk; + Crv_vybrk = cdata->vybrk; + Crv_clip = astGetClip( this ) & 1; + +/* Create a set of evenly spaced values between 0.0 and 1.0. These are the + offsets the edge of the plotting zone at which the mapping is tested. */ + for( i = 0; i < CRV_NPNT; i++ ){ + d[ i ] = ( (double) i)/( (double) CRV_NSEG ); + } + +/* Now set up the externals used to communicate with the Map2 function. + Map2 transforms a set of offsets between zero and one into a set of + corresponding graphics coordinates, with bad values substituted for any + offsets which correspond to points outside the domain of the mapping. */ + +/* The number of axes in the physical coordinate system (i.e. the current + Frame). */ + Map2_ncoord = astGetNout( this ); + +/* A pointer to the mapping from graphics world cordinates to physical + coordinates. */ + Map2_plot = this; + Map2_map = astGetMapping( this, AST__BASE, AST__CURRENT ); + +/* The graphics coordinates corresponding to an offset of zero (i.e. + the start of the line). */ + Map2_x0 = xa; + Map2_y0 = ya; + +/* The increments in X and Y between offset zero (the start of the + line) and offset 1 (the end of the line). */ + Map2_deltax = xb - xa; + Map2_deltay = yb - ya; + +/* Get the graphics coordinates corresponding to the initial set of + offsets. */ + Map2( CRV_NPNT, d, x, y, method, class, status GLOBALS_NAME ); + +/* Use Crv and Map2 to draw the intersection of the straight line with + the region containing valid physical coordinates. */ + Crv( this, d, x, y, 0, NULL, NULL, method, class, status ); + +/* End the current poly line. */ + Opoly( this, status ); + +/* Tidy up the static data used by Map2. */ + Map2( 0, NULL, NULL, NULL, method, class, status GLOBALS_NAME ); + +/* If no part of the curve could be drawn, set the number of breaks and the + length of the drawn curve to zero. */ + if( Crv_out ) { + Crv_nbrk = 0; + Crv_len = 0.0F; + +/* Otherwise, add an extra break to the returned structure at the position of + the last point to be plotted. */ + } else { + Crv_nbrk++; + if( Crv_nbrk > AST__PLOT_CRV_MXBRK ){ + astError( AST__CVBRK, "%s(%s): Number of breaks in curve " + "exceeds %d.", status, method, class, AST__PLOT_CRV_MXBRK ); + } else { + *(Crv_xbrk++) = (float) Crv_xl; + *(Crv_ybrk++) = (float) Crv_yl; + *(Crv_vxbrk++) = (float) -Crv_vxl; + *(Crv_vybrk++) = (float) -Crv_vyl; + } + } + +/* Store extra information about the curve in the returned structure, and + purge any zero length sections. */ + if( cdata ){ + cdata->length = Crv_len; + cdata->out = Crv_out; + cdata->nbrk = Crv_nbrk; + PurgeCdata( cdata, status ); + } + +/* Annul the Mapping. */ + Map2_map = astAnnul( Map2_map ); + +/* Return. */ + return; + +} + +static double **MakeGrid( AstPlot *this, AstFrame *frm, AstMapping *map, + int disk, int dim, double xlo, double xhi, + double ylo, double yhi, int nphy, AstPointSet **pset1, + AstPointSet **pset2, int norm, const char *method, + const char *class, int *status ){ +/* +* Name: +* MakeGrid + +* Purpose: +* Create a square grid of graphics coordinates and the corresponding +* physical coordinates. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* double **MakeGrid( AstPlot *this, AstFrame *frm, AstMapping *map, +* int disk, int dim, double xlo, double xhi, double ylo, +* double yhi, int nphy, AstPointSet **pset1, +* AstPointSet **pset2, int norm, const char *method, +* const char *class, int *status ){ + +* Class Membership: +* Plot member function. + +* Description: +* This function creates two PointSets, one holding a square grid of +* graphics coordinates covering the supplied area, and the other +* holding the corresponding physical coordinates. The points are +* stored row by row in the returned PointSets, i.e. if the cell size +* for the grid is (dx,dy), the first point is (xmin,ymin), followed +* by (xmin+dx,ymin), (xmin+2*dx,ymin), up to (xmin+(dim-1)*dx,ymin), +* followed by the next row (xmin,ymin+dy), (xmin+dx,ymin+dy), etc. + +* Parameters: +* this +* The Plot. +* frm +* A pointer to the Current Frame in the Plot. If this is supplied +* NULL, then a pointer is found within this function if required (i.e. +* if "norm" is non-zero). +* map +* The Mapping from graphics to physical coordinates, extracted from +* the Plot. +* disk +* If non-zero, the corners of the grid are omitted form the +* returned PointSets, resulting in a grid that is more disk like than +* rectangular. +* dim +* The number of samples along each edge of the grid. +* xlo +* The lower bound on the first axis of the region to be covered +* by the grid. +* xhi +* The upper bound on the first axis of the region to be covered +* by the grid. +* ylo +* The lower bound on the second axis of the region to be covered +* by the grid. +* yhi +* The upper bound on the second axis of the region to be covered +* by the grid. +* nphy +* The number of axes in the physical cooridinate system. +* pset1 +* A pointer to a location at which to store a pointer to the +* PointSet holding the graphics coordinates. +* pset2 +* A pointer to a location at which to store a pointer to the +* PointSet holding the physical coordinates. +* norm +* If non-zero the physical cooridnates are normalised using the +* Plot's astNorm method. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to the physical coordinate data stored in the PointSet +* "pset2". + +* Notes: +* - The returned PointSets should be annulled when no longer needed, +* using astAnnul. +* - NULL pointers are returned if an error has already occurred, or +* if this function should fail for any reason. +*/ + +/* Local Variables: */ + double **ptr1; /* Pointers to graphics axis values */ + double **ptr2; /* Pointers to physical axis values */ + int size; /* No. of points in the grid */ + +/* Initialise the returned pointers. */ + *pset1 = NULL; + *pset2 = NULL; + +/* Check the global error status. */ + if ( !astOK ) return NULL; + +/* Create two PointSets. We assume for the moment that they cover the + full grid, including corners. */ + size = dim*dim; + *pset1 = astPointSet( size, 2, "", status ); + *pset2 = astPointSet( size, nphy, "", status ); + +/* Get pointers to the data arrays for the two PointSets. */ + ptr1 = astGetPoints( *pset1 ); + ptr2 = astGetPoints( *pset2 ); + +/* Create a grid covering the supplied area. */ + size = GraphGrid( dim, disk, xlo, xhi, ylo, yhi, ptr1, status ); + +/* If the corners are being omitted, reduce the number of points in the + two PointSets. */ + if( disk ) { + astSetNpoint( *pset1, size ); + astSetNpoint( *pset2, size ); + } + +/* Transform these graphics positions to physical coordinates. */ + Trans( this, frm, map, *pset1, 1, *pset2, norm, method, class, status ); + +/* If an error has occurred, annul the two pointsets. */ + if( !astOK ){ + *pset1 = astAnnul( *pset1 ); + *pset2 = astAnnul( *pset2 ); + ptr2 = NULL; + } + +/* Return. */ + return ptr2; + +} + + +#if defined(THREAD_SAFE) +static int ManageLock( AstObject *this_object, int mode, int extra, + AstObject **fail, int *status ) { +/* +* Name: +* ManageLock + +* Purpose: +* Manage the thread lock on an Object. + +* Type: +* Private function. + +* Synopsis: +* #include "object.h" +* AstObject *ManageLock( AstObject *this, int mode, int extra, +* AstObject **fail, int *status ) + +* Class Membership: +* Plot member function (over-rides the astManageLock protected +* method inherited from the parent class). + +* Description: +* This function manages the thread lock on the supplied Object. The +* lock can be locked, unlocked or checked by this function as +* deteremined by parameter "mode". See astLock for details of the way +* these locks are used. + +* Parameters: +* this +* Pointer to the Object. +* mode +* An integer flag indicating what the function should do: +* +* AST__LOCK: Lock the Object for exclusive use by the calling +* thread. The "extra" value indicates what should be done if the +* Object is already locked (wait or report an error - see astLock). +* +* AST__UNLOCK: Unlock the Object for use by other threads. +* +* AST__CHECKLOCK: Check that the object is locked for use by the +* calling thread (report an error if not). +* extra +* Extra mode-specific information. +* fail +* If a non-zero function value is returned, a pointer to the +* Object that caused the failure is returned at "*fail". This may +* be "this" or it may be an Object contained within "this". Note, +* the Object's reference count is not incremented, and so the +* returned pointer should not be annulled. A NULL pointer is +* returned if this function returns a value of zero. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A local status value: +* 0 - Success +* 1 - Could not lock or unlock the object because it was already +* locked by another thread. +* 2 - Failed to lock a POSIX mutex +* 3 - Failed to unlock a POSIX mutex +* 4 - Bad "mode" value supplied. + +* Notes: +* - This function attempts to execute even if an error has already +* occurred. +*/ + +/* Local Variables: */ + AstPlot *this; /* Pointer to Plot structure */ + int result; /* Returned status value */ + +/* Initialise */ + result = 0; + +/* Check the supplied pointer is not NULL. */ + if( !this_object ) return result; + +/* Obtain a pointers to the Plot structure. */ + this = (AstPlot *) this_object; + +/* Invoke the ManageLock method inherited from the parent class. */ + if( !result ) result = (*parent_managelock)( this_object, mode, extra, + fail, status ); + +/* If defined, ensure the grfcontext KeyMap contained within the Plot is + locked, unlocked or checked. */ + if( this->grfcontext ) { + if( !result ) result = astManageLock( this->grfcontext, mode, extra, fail ); + +/* Also lock or unlock the associated object handle. */ + if( mode == AST__LOCK ) { + if( !result ) astLock( this->grfcontextID, extra ); + + } else if( mode == AST__UNLOCK ) { + if( !result ) astUnlock( this->grfcontextID, 0 ); + + } + } + + return result; + +} +#endif + +static void Map1( int n, double *dist, double *x, double *y, + const char *method, const char *class, + int *status GLOBALS_ARG ){ +/* +* Name: +* Map1 + +* Purpose: +* Find graphics coordinates at given distances along a curve +* parallel to a physical axis. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Map1( int n, double *dist, double *x, double *y, +* const char *method, const char *class, +* int *status [,AstGlobals *AST__GLOBALS] ) + +* Class Membership: +* Plot member function. + +* Description: +* The supplied distances are converted into physical coordinates +* using the scalings described by various external variables, and then +* these physical coordinates are mapped into graphics coordinates. + +* Parameters: +* n +* The number of points to map. Static resources are released but +* no points are mapped if zero is supplied. +* dist +* A pointer to an array holding "n" distances. A "dist" value of +* zero corresponds to the starting position supplied in external +* variable Map1_origin. A "dist" value of one corresponds to the +* finishing position which is a distance Map1_length away from +* Map1_origin, moving in the positive direction of the axis given +* by Map1_axis. "dist" values can be either linearly or +* logarithmically related to axis values (see Map1_log). +* x +* A pointer to an array in which to store the "n" graphics X +* coordinate values corresponding to the positions in "dist". +* y +* A pointer to an array in which to store the "n" graphics Y +* coordinate values corresponding to the positions in "dist". +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. +* AST__GLOBALS +* Only present if compiled with -DTHREAD_SAFE. It is a pointer to +* the structure holding the global data for the executing thread. +* It is passed as a function parameter, rather than being accessed +* within this function using the astGET_GLOBALS(NULL) macro (as +* other Object-less functions do) in order to avoid the time +* overheads of calling astGET_GLOBALS(NULL) . This function is +* time-critical. + +* External Variables: +* Map1_log = int (Read) +* If zero, then "dist" in learly related to axis value. Otherwise +* it is linearly related to log10(axis value). +* Map1_ncoord = int (Read) +* The number of axes in the physical coordinate system. +* Map1_axis = int (Read) +* The zero-based index of the axis which the curve follows (i.e. +* the axis which changes value along the curve). +* Map1_statics = Map1Statics * (Read and Write) +* Pointer to a structure holding other static data used by Map1. +* Map1_origin = const double * (Read) +* A pointer to an array holding the physical coordinate value on +* each axis at the start of the curve (i.e. at dist = 0.0). +* Map1_length = double (Read) +* The scale factor to convert "dist" values into increments +* along the physical axis given by Map1_axis. +* Map1_plot = AstPlot * (Read) +* A pointer to the Plot defining the mapping from graphics cordinates +* to physical coordinates. +* Map1_map = AstMapping * (Read) +* A pointer to the mapping from graphics cordinates to physical +* coordinates extracted from the Plot. +* Map1_frame = AstFrame * (Read) +* A pointer to the Current Frame in the Plot. +* Map1_norm = int (Read) +* A flag indicating if physical coordinate values which are not in +* the normal ranges of the corresponding axes should be considered +* bad. + +* Notes: +* - On the first call, this function allocates static resources which +* are used by subsequent invocation. These resources should be freed before +* calling this function with new values for any of the external variables, +* or when no longer needed, by calling this function with "n" supplied as +* zero. +* - If an error has already occurred, this runction returns without +* action ,except that if "n" is supplied as zero then static resources +* are released even if an error has already occurred. + +*/ + +/* Local Constants: */ + Map1Statics *statics; /* Pointer to structure holding static data */ + double *p; /* Pointer to next value */ + double axval; /* Axis origin value */ + int i, j; /* Loop counts */ + +/* Convert the global "void *" pointer to a Map1Statics pointer */ + statics = (Map1Statics *) Map1_statics; + +/* If zero points were supplied, release static resources and return. */ + if( n == 0 ){ + if( statics ) { + if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); + if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); + if( statics->work1 ) statics->work1 = (double *) astFree( (void *) statics->work1 ); + if( statics->work2 ) statics->work2 = (double *) astFree( (void *) statics->work2 ); + Map1_statics = astFree( statics ); + } + return; + } + +/* Otherwise, check the inherited global status. */ + if( !astOK ) return; + +/* Create and initialise a structure to hold extra static information if + this has not already been done. */ + if( !statics ) { + statics = astMalloc( sizeof( Map1Statics ) ); + if( statics ) { + statics->pset1 = NULL; + statics->pset2 = NULL; + statics->ptr1 = NULL; + statics->pax = NULL; + statics->ptr2[ 0 ] = NULL; + statics->ptr2[ 1 ] = NULL; + statics->work1 = NULL; + statics->work2 = NULL; + statics->nl = 0; + Map1_statics = statics; + } + } + +/* If the number of points to be mapped is different to last time, + set up some PointSets to store the specified number of points. */ + if( n != statics->nl ){ + statics->nl = n; + +/* Create a PointSet to hold the physical coordinates corresponding to + the supplied offsets. First annul any existing PointSet. */ + if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); + statics->pset1 = astPointSet( n, Map1_ncoord, "", status ); + statics->ptr1 = astGetPoints( statics->pset1 ); + +/* Create a PointSet to hold the corresponding graphics coordinates. + The supplied "x" and "y" arrays will be used to store the data + so we do not need to get pointers to the data using astGetPoints. First + annul any existing PointSet. */ + if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); + statics->pset2 = astPointSet( n, 2, "", status ); + +/* Get work space to hold two positions. */ + statics->work1 = (double *) astRealloc( (void *) statics->work1, + sizeof(double)*(size_t)Map1_ncoord ); + statics->work2 = (double *) astRealloc( (void *) statics->work2, + sizeof(double)*(size_t)Map1_ncoord ); + +/* Check the pointer can be used. */ + if( astOK ){ + +/* Store a pointer to the start of the memory which will be used to store + the physical data for the axis being drawn. */ + statics->pax = statics->ptr1[ Map1_axis ]; + +/* Fill the PointSet which is used to hold physical data with the physical + coordinates at the start of the curve. */ + for( i = 0; i < Map1_ncoord; i++ ){ + axval = Map1_origin[ i ]; + p = statics->ptr1[ i ]; + for( j = 0; j < n; j++ ) *(p++) = axval; + } + +/* Store the scale and offset to apply to the "dist" values. If Map1_log is + zero (linear axes) then applying these values gives axis value directly. + If Map1_log is non-zero (log axes) then applying these values gives + log10( axis value). */ + if( Map1_log ) { + statics->neg = ( Map1_origin[ Map1_axis ] < 0 ); + statics->axorig = log10( fabs( Map1_origin[ Map1_axis ] ) ); + statics->axscale = log10( fabs( Map1_origin[ Map1_axis ] + + Map1_length ) ) - statics->axorig; + } else { + statics->axorig = Map1_origin[ Map1_axis ]; + statics->axscale = Map1_length; + } + } + } + +/* Check the initialisation went OK (if done). */ + if( astOK ){ + +/* Loop round each offset along the curve, converting the normalised offset + in the range [0,1] to a physical coordinate and storing in PointSet 1. */ + p = statics->pax; + for( i = 0; i < n; i++){ + *(p++) = statics->axorig + statics->axscale*dist[ i ]; + } + if( Map1_log ) { + p = statics->pax; + for( i = 0; i < n; i++,p++ ){ + *p = statics->neg ? -pow( 10.0, *p ) : pow( 10.0, *p ); + } + } + +/* Store pointers to the results arrays in PointSet 2. */ + statics->ptr2[ 0 ] = x; + statics->ptr2[ 1 ] = y; + astSetPoints( statics->pset2, statics->ptr2 ); + +/* Map all the positions into graphics coordinates. */ + (void) Trans( Map1_plot, NULL, Map1_map, statics->pset1, 0, statics->pset2, 1, method, class, status ); + +/* If points not in their normal ranges are to be set bad... */ + if( Map1_norm ) { + +/* The following code simply normalizes the physical position, and if this + produces any change, the graphics positions are set bad. */ + for( i = 0; i < n; i++){ + for( j = 0; j < Map1_ncoord; j++) statics->work1[j] = statics->ptr1[j][i]; + astNorm( Map1_frame, statics->work1 ); + for( j = 0; j < Map1_ncoord; j++) { + if( !astEQUALS( statics->work1[j], statics->ptr1[j][i], 1.0E8 ) ) { + statics->ptr2[0][i] = AST__BAD; + statics->ptr2[1][i] = AST__BAD; + break; + } + } + } + } + } + +/* Return. */ + return; + +} + +static void Map2( int n, double *dist, double *x, double *y, + const char *method, const char *class, + int *status GLOBALS_ARG ){ +/* +* Name: +* Map2 + +* Purpose: +* Find which graphics coordinates have good physical coordinates +* at given distances along a straight line. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Map2( int n, double *dist, double *x, double *y, +* const char *method, const char *class, +* int *status [,AstGlobals *AST__GLOBALS] ) + +* Class Membership: +* Plot member function. + +* Description: +* The supplied distances refer to the distance along a straight line +* in the graphics coordinate system. The returned graphics coordinates +* correspond to the supplied distances, except that any position for +* which there are no defined physical coordinates is returned bad. + +* Parameters: +* n +* The number of points to map. Static resources are released but +* no points are mapped if zero is supplied. +* dist +* A pointer to an array holding "n" distances. A "dist" value of +* zero corresponds to the graphics position supplied in external +* variables (Map2_x0, Map2_y0). A "dist" value of one corresponds to +* the graphics position which is offset from the start by the vector +* (Map2_deltax, Map2_deltay). +* x +* A pointer to an array in which to store the "n" graphics X +* coordinate values corresponding to the positions in "dist", +* except that any which have no corresponding physical coordinates +* are set to AST__BAD. +* y +* A pointer to an array in which to store the "n" graphics Y +* coordinate values corresponding to the positions in "dist", +* except that any which have no corresponding physical coordinates +* are set to AST__BAD. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. +* AST__GLOBALS +* Only present if compiled with -DTHREAD_SAFE. It is a pointer to +* the structure holding the global data for the executing thread. +* It is passed as a function parameter, rather than being accessed +* within this function using the astGET_GLOBALS(NULL) macro (as +* other Object-less functions do) in order to avoid the time +* overheads of calling astGET_GLOBALS(NULL) . This function is +* time-critical. + +* External Variables: +* Map2_ncoord = int (Read) +* The number of axes in the physical coordinate system. +* Map2_x0 = double (Read) +* The graphics X coordinate at the start of the line (i.e. at dist +* = 0.0). +* Map2_y0 = double (Read) +* The graphics Y coordinate at the start of the line (i.e. at dist +* = 0.0). +* Map2_deltax = double (Read) +* The increment along the graphics X axis between the start and +* end of the line. +* Map2_deltay = double (Read) +* The increment along the graphics Y axis between the start and +* end of the line. +* Map2_plot = AstPlot * (Read) +* A pointer to the Plot defining the mapping from graphics cordinates +* to physical coordinates. +* Map2_map = AstMapping * (Read) +* A pointer to the mapping from graphics cordinates to physical +* coordinates, extracted from the Plot. +* Map2_statics = Map2Statics * (Read and Write) +* Pointer to a structure holding other static data used by Map2. + +* Notes: +* - On the first call, this function allocates static resources which +* are used by subsequent invocation. These resources should be freed before +* calling this function with new values for any of the external variables, +* or when no longer needed, by calling this function with "n" supplied as +* zero. +* - If an error has already occurred, this runction returns without +* action ,except that if "n" is supplied as zero then static resources +* are released even if an error has already occurred. + +*/ +/* Local Constants: */ + Map2Statics *statics; /* Pointer to structure holding static data */ + int i, j; /* Loop counts */ + double *p; /* Pointer to next physical value */ + double *px; /* Pointer to next x graphics value */ + double *py; /* Pointer to next y graphics value */ + +/* Convert the global "void *" pointer to a Map2Statics pointer */ + statics = (Map2Statics *) Map2_statics; + +/* If zero points were supplied, release static resources and return. */ + if( n == 0 ){ + if( statics ) { + if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); + if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); + Map2_statics = astFree( statics ); + } + return; + } + +/* Otherwise, check the inherited global status. */ + if( !astOK ) return; + +/* Create and initialise a structure to hold extra static information if + this has not already been done. */ + if( !statics ) { + statics = astMalloc( sizeof( Map2Statics ) ); + if( statics ) { + statics->pset1 = NULL; + statics->pset2 = NULL; + statics->ptr2 = NULL; + statics->ptr1[ 0 ] = NULL; + statics->ptr1[ 1 ] = NULL; + statics->nl = 0; + Map2_statics = statics; + } + } + +/* If the number of points to be mapped is different to last time, + set up some PointSets to store the specified number of points. */ + if( n != statics->nl ){ + statics->nl = n; + +/* Create a PointSet to hold the graphics coordinates corresponding to + the supplied offsets. The supplied arrays will be used to hold the + data for this PointSet, and so astGetPoints is not called. */ + if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); + statics->pset1 = astPointSet( n, 2, "", status ); + +/* Create a PointSet to hold the corresponding physical coordinates, and + get pointers to the associated axis values. */ + if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); + statics->pset2 = astPointSet( n, Map2_ncoord, "", status ); + statics->ptr2 = astGetPoints( statics->pset2 ); + } + + +/* Check the initialisation went OK (if done). */ + if( astOK ){ + +/* Store pointers to the results arrays in PointSet 1. */ + statics->ptr1[ 0 ] = x; + statics->ptr1[ 1 ] = y; + astSetPoints( statics->pset1, statics->ptr1 ); + +/* Loop round each offset along the curve, converting the normalised offset + in the range [0,1] to graphics coordinate and storing in PointSet 1. */ + px = x; + py = y; + for( i = 0; i < n; i++){ + *(px++) = Map2_x0 + Map2_deltax*dist[ i ]; + *(py++) = Map2_y0 + Map2_deltay*dist[ i ]; + } + +/* Map all the positions into physical coordinates. */ + (void) Trans( Map2_plot, NULL, Map2_map, statics->pset1, 1, statics->pset2, 0, method, class, status ); + +/* Check the physical coordinates for bad values, setting the corresponding + graphics coordinates bad. */ + for( j = 0; j < Map2_ncoord; j++ ){ + p = statics->ptr2[ j ]; + px = x; + py = y; + + for( i = 0; i < n; i++){ + if( *(p++) == AST__BAD ){ + *(px++) = AST__BAD; + *(py++) = AST__BAD; + } else { + px++; + py++; + } + } + } + } + +/* Return. */ + return; + +} + +static void Map3( int n, double *dist, double *x, double *y, + const char *method, const char *class, + int *status GLOBALS_ARG ){ +/* +* Name: +* Map3 + +* Purpose: +* Find graphics coordinates at given distances along a geodesic curve +* between two physical coordinate positions. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Map3( int n, double *dist, double *x, double *y, +* const char *method, const char *class, +* int *status [,AstGlobals *AST__GLOBALS] ) + +* Class Membership: +* Plot member function. + +* Description: +* The supplied distances are converted into physical offsets along the +* geodesic curve joining the starting and finishing points given by +* externals Map3_origin and Map3_end. The physical coordinates at these +* offsets are found, and transformed into graphics coordinates. + +* Parameters: +* n +* The number of points to map. Static resources are released but +* no points are mapped if zero is supplied. +* dist +* A pointer to an array holding "n" distances. A "dist" value of +* zero corresponds to the starting position supplied in external +* variable Map3_origin. A "dist" value of one corresponds to the +* finishing position given by Map3_end. +* x +* A pointer to an array in which to store the "n" graphics X +* coordinate values corresponding to the positions in "dist". +* y +* A pointer to an array in which to store the "n" graphics Y +* coordinate values corresponding to the positions in "dist". +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. +* AST__GLOBALS +* Only present if compiled with -DTHREAD_SAFE. It is a pointer to +* the structure holding the global data for the executing thread. +* It is passed as a function parameter, rather than being accessed +* within this function using the astGET_GLOBALS(NULL) macro (as +* other Object-less functions do) in order to avoid the time +* overheads of calling astGET_GLOBALS(NULL) . This function is +* time-critical. + +* External Variables: +* Map3_ncoord = int (Read) +* The number of axes in the physical coordinate system. +* Map3_origin = const double * (Read) +* A pointer to an array holding the physical coordinate value on +* each axis at the start of the curve (i.e. at dist = 0.0). +* Map3_end = const double * (Read) +* A pointer to an array holding the physical coordinate value on +* each axis at the end of the curve (i.e. at dist = 1.0). +* Map3_scale = double (Read) +* The scale factor to convert "dist" values into physical offsets +* along the geodesic curve. +* Map3_statics = Map3Statics * (Read and Write) +* Pointer to a structure holding other static data used by Map3. +* Map3_plot = AstPlot * (Read) +* A pointer to the Plot defining the mapping from graphics cordinates +* to physical coordinates. +* Map3_map = AstMapping * (Read) +* A pointer to the mapping from graphics cordinates to physical +* coordinates extracted from the Plot. +* Map3_frame = AstFrame * (Read) +* A pointer to the Current Frame in the Plot. + +* Notes: +* - On the first call, this function allocates static resources which +* are used by subsequent invocation. These resources should be freed before +* calling this function with new values for any of the external variables, +* or when no longer needed, by calling this function with "n" supplied as +* zero. +* - If an error has already occurred, this runction returns without +* action ,except that if "n" is supplied as zero then static resources +* are released even if an error has already occurred. + +*/ + +/* Local Constants: */ + Map3Statics *statics; /* Pointer to structure holding static data */ + int i, j; /* Loop counts */ + +/* Convert the global "void *" pointer to a Map3Statics pointer */ + statics = (Map3Statics *) Map3_statics; + +/* If zero points were supplied, release static resources and return. */ + if( n == 0 ){ + if( statics ) { + if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); + if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); + if( statics->pos ) statics->pos = (double *) astFree( (void *) statics->pos ); + Map3_statics = astFree( statics ); + } + return; + } + +/* Otherwise, check the inherited global status. */ + if( !astOK ) return; + +/* Create and initialise a structure to hold extra static information if + this has not already been done. */ + if( !statics ) { + statics = astMalloc( sizeof( Map3Statics ) ); + if( statics ) { + statics->pset1 = NULL; + statics->pset2 = NULL; + statics->ptr1 = NULL; + statics->ptr2[ 0 ] = NULL; + statics->ptr2[ 1 ] = NULL; + statics->nc = 0; + statics->nl = 0; + statics->pos = NULL; + Map3_statics = statics; + } + } + +/* If the number of points to be mapped is different to last time, + set up some PointSets to store the specified number of points. */ + if( n != statics->nl ){ + statics->nl = n; + +/* Create a PointSet to hold the physical coordinates corresponding to + the supplied offsets. First annul any existing PointSet. */ + if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); + statics->pset1 = astPointSet( n, Map3_ncoord, "", status ); + statics->ptr1 = astGetPoints( statics->pset1 ); + +/* Create a PointSet to hold the corresponding graphics coordinates. + The supplied "x" and "y" arrays will be used to store the data + so we do not need to get pointers to the data using astGetPoints. First + annul any existing PointSet. */ + if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); + statics->pset2 = astPointSet( n, 2, "", status ); + + } + +/* If the number of physical axes is different to last time, allocate + memory to hold a single physical position. */ + if( statics->nc != Map3_ncoord ){ + statics->nc = Map3_ncoord; + statics->pos = (double *) astMalloc( sizeof(double)*(size_t)Map3_ncoord ); + } + +/* Check the initialisation went OK (if done). */ + if( astOK ){ + +/* Loop round each offset along the curve, converting the normalised offset + in the range [0,1] to a physical offset, and then into a physical + position, and store in PointSet 1. */ + for( i = 0; i < n; i++){ + astOffset( Map3_frame, Map3_origin, Map3_end, Map3_scale*dist[ i ], + statics->pos ); + + for( j = 0; j < Map3_ncoord; j++ ){ + statics->ptr1[ j ][ i ] = statics->pos[ j ]; + } + + } + +/* Store pointers to the results arrays in PointSet 2. */ + statics->ptr2[ 0 ] = x; + statics->ptr2[ 1 ] = y; + astSetPoints( statics->pset2, statics->ptr2 ); + +/* Map all the positions into graphics coordinates. */ + (void) Trans( Map3_plot, NULL, Map3_map, statics->pset1, 0, statics->pset2, 1, method, class, status ); + } + +/* Return. */ + return; + +} + +static void Map4( int n, double *dist, double *x, double *y, + const char *method, const char *class, + int *status GLOBALS_ARG ){ +/* +* Name: +* Map4 + +* Purpose: +* Find graphics coordinates at given distances along a user +* specified curve. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Map4( int n, double *dist, double *x, double *y, +* const char *method, const char *class, +* int *status [,AstGlobals *AST__GLOBALS] ) + +* Class Membership: +* Plot member function. + +* Description: +* The supplied distances are converted into physical coordinates using +* the Mapping Map4_umap. These physical coordinates are transformed into +* graphics coordinates. + +* Parameters: +* n +* The number of points to map. Static resources are released but +* no points are mapped if zero is supplied. +* dist +* A pointer to an array holding "n" distances. A "dist" value of +* zero corresponds to the starting position supplied in external +* variable Map3_origin. A "dist" value of one corresponds to the +* finishing position given by Map3_end. +* x +* A pointer to an array in which to store the "n" graphics X +* coordinate values corresponding to the positions in "dist". +* y +* A pointer to an array in which to store the "n" graphics Y +* coordinate values corresponding to the positions in "dist". +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. +* AST__GLOBALS +* Only present if compiled with -DTHREAD_SAFE. It is a pointer to +* the structure holding the global data for the executing thread. +* It is passed as a function parameter, rather than being accessed +* within this function using the astGET_GLOBALS(NULL) macro (as +* other Object-less functions do) in order to avoid the time +* overheads of calling astGET_GLOBALS(NULL) . This function is +* time-critical. + +* External Variables: +* Map4_ncoord = int (Read) +* The number of axes in the physical coordinate system. +* Map4_plot = AstPlot * (Read) +* A pointer to the Plot defining the mapping from graphics cordinates +* to physical coordinates. +* Map4_map = AstMapping * (Read) +* A pointer to the mapping from graphics cordinates to physical +* coordinates extracted from the Plot. +* Map4_statics = Map4Statics * (Read and Write) +* Pointer to a structure holding other static data used by Map4. +* Map4_umap = AstMapping * (Read) +* A pointer to the mapping from distance along the curve to physical +* coordinates. + +* Notes: +* - On the first call, this function allocates static resources which +* are used by subsequent invocation. These resources should be freed before +* calling this function with new values for any of the external variables, +* or when no longer needed, by calling this function with "n" supplied as +* zero. +* - If an error has already occurred, this runction returns without +* action ,except that if "n" is supplied as zero then static resources +* are released even if an error has already occurred. + +*/ + +/* Local Variables: */ + Map4Statics *statics; /* Pointer to structure holding static data */ + double *ptr1[ 1 ]; /* Pointer to distances data */ + double *ptr3[ 2 ]; /* Pointers to graphics coord data */ + +/* Convert the global "void *" pointer to a Map4Statics pointer */ + statics = (Map4Statics *) Map4_statics; + +/* If zero points were supplied, release static resources and return. */ + if( n == 0 ){ + if( statics ) { + if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); + if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); + if( statics->pset3 ) statics->pset3 = astAnnul( statics->pset3 ); + Map4_statics = astFree( statics ); + } + return; + } + +/* Otherwise, check the inherited global status. */ + if( !astOK ) return; + +/* Create and initialise a structure to hold extra static information if + this has not already been done. */ + if( !statics ) { + statics = astMalloc( sizeof( Map4Statics ) ); + if( statics ) { + statics->pset1 = NULL; + statics->pset2 = NULL; + statics->pset3 = NULL; + statics->nl = 0; + Map4_statics = statics; + } + } + +/* If the number of points to be mapped is different to last time, + set up some PointSets to store the specified number of points. */ + if( n != statics->nl ){ + statics->nl = n; + +/* Create a PointSet to hold the distances along the curve. First annul any + existing PointSet. */ + if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); + statics->pset1 = astPointSet( n, 1, "", status ); + +/* Create a PointSet to hold the physical coordinates corresponding to + the supplied distances. First annul any existing PointSet. */ + if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); + statics->pset2 = astPointSet( n, Map4_ncoord, "", status ); + +/* Create a PointSet to hold the corresponding graphics coordinates. + First annul any existing PointSet. */ + if( statics->pset3 ) statics->pset3 = astAnnul( statics->pset3 ); + statics->pset3 = astPointSet( n, 2, "", status ); + + } + +/* Check the initialisation went OK (if done). */ + if( astOK ){ + +/* Use Map4_umap to convert the supplied distances into physical coords + (i.e. coords in the current Frame of the Plot). */ + ptr1[ 0 ] = dist; + astSetPoints( statics->pset1, ptr1 ); + (void) astTransform( Map4_umap, statics->pset1, 1, statics->pset2 ); + +/* Store pointers to the results arrays in PointSet 2. */ + ptr3[ 0 ] = x; + ptr3[ 1 ] = y; + astSetPoints( statics->pset3, ptr3 ); + +/* Now transform these physical coords into graphical coords, + incorporating clipping. */ + (void) Trans( Map4_plot, NULL, Map4_map, statics->pset2, 0, statics->pset3, 1, method, class, status ); + } + +/* Return. */ + return; + +} + +static void Map5( int n, double *dist, double *x, double *y, + const char *method, const char *class, + int *status GLOBALS_ARG ){ +/* +* Name: +* Map5 + +* Purpose: +* Find graphics coordinates at given distances along the boundary of +* a Region. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Map5( int n, double *dist, double *x, double *y, +* const char *method, const char *class, +* int *status [,AstGlobals *AST__GLOBALS] ) + +* Class Membership: +* Plot member function. + +* Description: +* The supplied distances are converted into physical coordinates +* using the Region specified by an external variable, and then +* these physical coordinates are mapped into graphics coordinates. + +* Parameters: +* n +* The number of points to map. Static resources are released but +* no points are mapped if zero is supplied. +* dist +* A pointer to an array holding "n" distances. A "dist" value of +* zero corresponds to the starting position supplied in external +* variable Map1_origin. A "dist" value of one corresponds to the +* finishing position which is a distance Map1_length away from +* Map1_origin, moving in the positive direction of the axis given +* by Map1_axis. "dist" values can be either linearly or +* logarithmically related to axis values (see Map1_log). +* x +* A pointer to an array in which to store the "n" graphics X +* coordinate values corresponding to the positions in "dist". +* y +* A pointer to an array in which to store the "n" graphics Y +* coordinate values corresponding to the positions in "dist". +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. +* AST__GLOBALS +* Only present if compiled with -DTHREAD_SAFE. It is a pointer to +* the structure holding the global data for the executing thread. +* It is passed as a function parameter, rather than being accessed +* within this function using the astGET_GLOBALS(NULL) macro (as +* other Object-less functions do) in order to avoid the time +* overheads of calling astGET_GLOBALS(NULL) . This function is +* time-critical. + +* External Variables: +* Map1_log = int (Read) +* If zero, then "dist" in learly related to axis value. Otherwise +* it is linearly related to log10(axis value). +* Map1_ncoord = int (Read) +* The number of axes in the physical coordinate system. +* Map1_axis = int (Read) +* The zero-based index of the axis which the curve follows (i.e. +* the axis which changes value along the curve). +* Map1_statics = Map1Statics * (Read and Write) +* Pointer to a structure holding other static data used by Map1. +* Map1_origin = const double * (Read) +* A pointer to an array holding the physical coordinate value on +* each axis at the start of the curve (i.e. at dist = 0.0). +* Map1_length = double (Read) +* The scale factor to convert "dist" values into increments +* along the physical axis given by Map1_axis. +* Map1_plot = AstPlot * (Read) +* A pointer to the Plot defining the mapping from graphics cordinates +* to physical coordinates. +* Map1_map = AstMapping * (Read) +* A pointer to the mapping from graphics cordinates to physical +* coordinates extracted from the Plot. +* Map1_frame = AstFrame * (Read) +* A pointer to the Current Frame in the Plot. +* Map1_norm = int (Read) +* A flag indicating if physical coordinate values which are not in +* the normal ranges of the corresponding axes should be considered +* bad. + +* Notes: +* - On the first call, this function allocates static resources which +* are used by subsequent invocation. These resources should be freed before +* calling this function with new values for any of the external variables, +* or when no longer needed, by calling this function with "n" supplied as +* zero. +* - If an error has already occurred, this runction returns without +* action ,except that if "n" is supplied as zero then static resources +* are released even if an error has already occurred. + +*/ + +/* Local Constants: */ + Map5Statics *statics; /* Pointer to structure holding static data */ + +/* Convert the global "void *" pointer to a Map5Statics pointer */ + statics = (Map5Statics *) Map5_statics; + +/* If zero points were supplied, release static resources and return. */ + if( n == 0 ){ + if( statics ) { + if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); + if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); + Map5_statics = astFree( statics ); + } + return; + } + +/* Otherwise, check the inherited global status. */ + if( !astOK ) return; + +/* Create and initialise a structure to hold extra static information if + this has not already been done. */ + if( !statics ) { + statics = astMalloc( sizeof( Map3Statics ) ); + if( statics ) { + statics->pset1 = NULL; + statics->pset2 = NULL; + statics->ptr1 = NULL; + statics->ptr2[ 0 ] = NULL; + statics->ptr2[ 1 ] = NULL; + statics->nl = 0; + Map5_statics = statics; + } + } + +/* If the number of points to be mapped is different to last time, + set up some PointSets to store the specified number of points. */ + if( n != statics->nl ){ + statics->nl = n; + +/* Create a PointSet to hold the physical coordinates corresponding to + the supplied offsets. First annul any existing PointSet. */ + if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); + statics->pset1 = astPointSet( n, Map5_ncoord, "", status ); + statics->ptr1 = astGetPoints( statics->pset1 ); + +/* Create a PointSet to hold the corresponding graphics coordinates. + The supplied "x" and "y" arrays will be used to store the data + so we do not need to get pointers to the data using astGetPoints. First + annul any existing PointSet. */ + if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); + statics->pset2 = astPointSet( n, 2, "", status ); + } + +/* Get the physical coords at the required positions along the Region + border. */ + astRegTrace( Map5_region, n, dist, statics->ptr1 ); + +/* Store pointers to the results arrays in PointSet 2. */ + statics->ptr2[ 0 ] = x; + statics->ptr2[ 1 ] = y; + astSetPoints( statics->pset2, statics->ptr2 ); + +/* Map all the positions into graphics coordinates. */ + (void) Trans( Map5_plot, NULL, Map5_map, statics->pset1, 0, + statics->pset2, 1, method, class, status ); + +/* Return. */ + return; +} + +static void Mark( AstPlot *this, int nmark, int ncoord, int indim, + const double *in, int type, int *status ){ +/* +*++ +* Name: +c astMark +f AST_MARK + +* Purpose: +* Draw a set of markers for a Plot. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "plot.h" +c void astMark( AstPlot *this, int nmark, int ncoord, int indim, +c const double *in, int type ) +f CALL AST_MARK( THIS, NMARK, NCOORD, INDIM, IN, TYPE, STATUS ) + +* Class Membership: +* Plot method. + +* Description: +c This function draws a set of markers (symbols) at positions +f This routine draws a set of markers (symbols) at positions +* specified in the physical coordinate system of a Plot. The +* positions are transformed into graphical coordinates to +* determine where the markers should appear within the plotting +* area. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +c nmark +f NMARK = INTEGER (Given) +* The number of markers to draw. This may be zero, in which +* case nothing will be drawn. +c ncoord +f NCOORD = INTEGER (Given) +* The number of coordinates being supplied for each mark +* (i.e. the number of axes in the current Frame of the Plot, as +* given by its Naxes attribute). +c indim +f INDIM = INTEGER (Given) +c The number of elements along the second dimension of the "in" +f The number of elements along the first dimension of the IN +* array (which contains the marker coordinates). This value is +* required so that the coordinate values can be correctly +* located if they do not entirely fill this array. The value +c given should not be less than "nmark". +f given should not be less than NMARK. +c in +f IN( INDIM, NCOORD ) = DOUBLE PRECISION (Given) +c The address of the first element of a 2-dimensional array of +c shape "[ncoord][indim]" giving the +c physical coordinates of the points where markers are to be +c drawn. These should be stored such that the value of +c coordinate number "coord" for input mark number "mark" is +c found in element "in[coord][mark]". +f A 2-dimensional array giving the physical coordinates of the +f points where markers are to be drawn. These should be +f stored such that the value of coordinate number COORD for +f input mark number MARK is found in element IN(MARK,COORD). +c type +f TYPE = INTEGER (Given) +* A value specifying the type (e.g. shape) of marker to be +* drawn. The set of values which may be used (and the shapes +* that will result) is determined by the underlying graphics +* system. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +* - Markers are not drawn at positions which have any coordinate +* equal to the value AST__BAD (or where the transformation into +* graphical coordinates yields coordinates containing the value +* AST__BAD). +c - If any marker position is clipped (see astClip), then the +f - If any marker position is clipped (see AST_CLIP), then the +* entire marker is not drawn. +* - An error results if the base Frame of the Plot is not 2-dimensional. +* - An error also results if the transformation between the +* current and base Frames of the Plot is not defined (i.e. the +* Plot's TranInverse attribute is zero). +*-- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstMapping *mapping; /* Pointer to graphics->physical mapping */ + AstPointSet *pset1; /* PointSet holding physical positions */ + AstPointSet *pset2; /* PointSet holding graphics positions */ + const char *class; /* Object class */ + const char *method; /* Current method */ + const double **ptr1; /* Pointer to physical positions */ + double **ptr2; /* Pointer to graphics positions */ + double *xpd; /* Pointer to next double precision x value */ + double *ypd; /* Pointer to next double precision y value */ + double xx; /* X axis value */ + double yy; /* Y axis value */ + float *x; /* Pointer to single precision x values */ + float *xpf; /* Pointer to next single precision x value */ + float *y; /* Pointer to single precision y values */ + float *ypf; /* Pointer to next single precision y value */ + int axis; /* Axis index */ + int clip; /* Clips marks at plot boundary? */ + int i; /* Loop count */ + int naxes; /* No. of axes in the base Frame */ + int nn; /* Number of good marker positions */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Store the current method and class for inclusion in error messages + generated by lower level functions. */ + method = "astMark"; + class = astClass( this ); + +/* Check the base Frame of the Plot is 2-D. */ + naxes = astGetNin( this ); + if( naxes != 2 && astOK ){ + astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " + "Frame of the supplied %s is invalid - this number should " + "be 2.", status, method, class, naxes, class ); + } + +/* Also validate the input array dimension argument. */ + if ( astOK && ( indim < nmark ) ) { + astError( AST__DIMIN, "%s(%s): The input array dimension value " + "(%d) is invalid.", status, method, class, indim ); + astError( AST__DIMIN, "This should not be less than the number of " + "markers being drawn (%d).", status, nmark ); + } + +/* Initialise the bounding box for primatives produced by this call. */ + if( !Boxp_freeze ) { + Boxp_lbnd[ 0 ] = FLT_MAX; + Boxp_lbnd[ 1 ] = FLT_MAX; + Boxp_ubnd[ 0 ] = FLT_MIN; + Boxp_ubnd[ 1 ] = FLT_MIN; + } + +/* Indicate that the GRF module should re-calculate it's cached values + (in case the state of the graphics system has changed since the last + thing was drawn). */ + RESET_GRF; + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + astGrfAttrs( this, AST__MARKS_ID, 1, GRF__MARK, method, class ); + +/* Create a PointSet to hold the supplied physical coordinates. */ + pset1 = astPointSet( nmark, ncoord, "", status ); + +/* Allocate memory to hold pointers to the first value on each axis. */ + ptr1 = (const double **) astMalloc( sizeof( const double * )* + (size_t)( ncoord )); + +/* Check the pointer can be used, then store pointers to the first value + on each axis. */ + if( astOK ){ + for( axis = 0; axis < ncoord; axis++ ){ + ptr1[ axis ] = in + axis*indim; + } + } + +/* Store these pointers in the PointSet. */ + astSetPoints( pset1, (double **) ptr1 ); + +/* Transform the supplied data from the current frame (i.e. physical + coordinates) to the base frame (i.e. graphics coordinates) using + the inverse Mapping defined by the Plot. */ + mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); + pset2 = Trans( this, NULL, mapping, pset1, 0, NULL, 0, method, class, status ); + mapping = astAnnul( mapping ); + +/* Get pointers to the graphics coordinates. */ + ptr2 = astGetPoints( pset2 ); + +/* Allocate memory to hold single precision versions of the graphics + coordinates. */ + x = (float *) astMalloc( sizeof( float )*(size_t) nmark ); + y = (float *) astMalloc( sizeof( float )*(size_t) nmark ); + +/* Check the pointers can be used. */ + if( astOK ){ + +/* Store pointers to the next single and double precision x and y + values. */ + xpf = x; + ypf = y; + xpd = ptr2[ 0 ]; + ypd = ptr2[ 1 ]; + +/* Convert the double precision values to single precision, rejecting + any bad marker positions. If clipping is switched on, also clip any + markers with centres outside the plotting area. */ + clip = astGetClip( this ) & 2; + nn = 0; + for( i = 0; i < nmark; i++ ){ + if( *xpd != AST__BAD && *ypd != AST__BAD ){ + xx = *(xpd++); + yy = *(ypd++); + if( !clip || ( xx >= this->xlo && xx <= this->xhi && + yy >= this->ylo && yy <= this->yhi ) ) { + nn++; + *(xpf++) = (float) xx; + *(ypf++) = (float) yy; + } + } else { + xpd++; + ypd++; + } + } + +/* Draw the remaining markers. */ + GMark( this, nn, x, y, type, method, class, status ); + + } + +/* Free the memory used to store single precision graphics coordinates. */ + x = (float *) astFree( (void *) x ); + y = (float *) astFree( (void *) y ); + +/* Annul the PointSets. */ + pset1 = astAnnul( pset1 ); + pset2 = astAnnul( pset2 ); + +/* Free the memory holding the pointers to the first value on each axis. */ + ptr1 = (const double **) astFree( (void *) ptr1 ); + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, AST__MARKS_ID, 0, GRF__MARK, method, class ); + +/* Return */ + return; +} + +static void Mirror( AstPlot *this, int axis, int *status ){ +/* +*+ +* Name: +* astMirror + +* Purpose: +* Flip a graphics axis of a Plot. + +* Type: +* Protected virtual function. + +* Synopsis: +* #include "plot.h" +* void astMirror( AstPlot *this, int axis ) + +* Class Membership: +* Plot method. + +* Description: +* This function referses the direction of a specified graphics axis +* in the Plot. + +* Parameters: +* this +* Pointer to a Plot. +* axis +* The zero-based axis of the axis to mirror. + +*- +*/ + +/* Check the global status. */ + if( !astOK ) return; + + if( axis == 0 ) { + this->xrev = ( this->xrev == 0 ); + + } else if( axis == 1 ){ + this->yrev = ( this->yrev == 0 ); + + } else { + astError( AST__INTER, "astMirror(%s): Illegal axis index (%d) " + "supplied (internal AST programming error).", status, + astGetClass( this ), axis ); + } +} + +static void Norm1( AstMapping *map, int axis, int nv, double *vals, + double refval, double width, int *status ){ +/* +* Name: +* Norm1 + +* Purpose: +* Use a Mapping to normalize an array of axis values. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Norm1( AstMapping *map, int axis, int nv, double *vals, +* double refval, double width, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* The normalization of a position in physical space has two parts; +* firstly, the Mapping may determine a form of normalization; +* secondly, the Frame may provide an additional normalizion by the +* astNorm method. This function implements normalization using a +* Mapping, by transforming the physical position into Graphics position, +* and then back into a physical position. For instance, if the Mapping +* represents a mapping of Cartesian graphics axes onto a 2D polar +* coordinate system, a physical theta value of 3.PI will be normalized by +* the Mapping into a theta value of 1.PI (probably, but it depends on +* the Mapping). In this case, the Mapping normalization may well be the +* only normalization available, since the 2D polar coord. system will +* probably use a simple Frame to represent the (radius,theta) system, +* and a simple Frame defines no normalization (i.e. the astNorm method +* returns the supplied position unchanged). +* +* Complications arise though because it is not possible to normalise +* a single axis value - you can only normalize a complete position. +* Therefore some value must be supplied for the other axis. We +* should use the LabelAt value, but we do not yet know what the LabelAt +* value will be. Instead, we try first using the supplied "refval" +* which should be close to the mode of the other aixs values. Usually +* the value used is not very important. However, for some complex +* projections (such as quad-cubes, TSC, etc) the choice can be more +* critical since some positions on the ksy correspond to undefined +* graphics positions (e.g the face edges in a TSC projection). +* Therefore, if the supplied refval results in any positions being +* undefined we refine the process by transforming the undefined +* positaons again using a different refval. We do this twice to bump +* up the likelihood of finding a suitable reference value. + +* Parameters: +* mapping +* The Mapping from Graphics Frame to the current Frame. +* axis +* The index of the axis for which values are supplied in "vals". +* nv +* The number of values supplied in "vals". +* vals +* Pointer to an array of axis values. On exit they are normalized. +* refval +* The preffered constant value to use for the other axis when +* normalizing the values in "vals". +* width +* The range of used values for the other axis. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstPointSet *pset1; /* PointSet holding physical coords */ + AstPointSet *pset2; /* PointSet holding graphics coords */ + double **ptr1; /* Pointer to physical coords data */ + double *a; /* Pointer to next axis value */ + double *b; /* Pointer to next axis value */ + int i; /* Loop count */ + int itry; /* Loop count for re-try loop */ + int nbad; /* No. of bad values found after transformation */ + int *flags; /* Pointer to flags array */ + +/* Check the inherited global status. */ + if( !astOK ) return; + +/* Store the supplied positions in a PointSet. */ + pset1 = astPointSet( nv, 2, "", status ); + ptr1 = astGetPoints( pset1 ); + if( astOK ) { + a = ptr1[ axis ]; + b = ptr1[ 1 - axis ]; + for( i = 0; i < nv; i++){ + *(a++) = vals[ i ]; + *(b++) = refval; + } + } + +/* Transform the supplied positions into the Base Frame. */ + pset2 = astTransform( map, pset1, 0, NULL ); + +/* Transform the Base Frame positions back into the Current Frame. */ + (void) astTransform( map, pset2, 1, pset1 ); + +/* Allocate memory to hold a flag for each position which is non-zero if + we currently have a good axis value to return for the position. */ + flags = (int *) astMalloc( sizeof(int)* (size_t) nv ); + +/* If good, store these values back in the supplied array. If the + transformed values are bad, retain the original good values for the + moment in "vals", and also copy the good values back into pset1. So + at the end, pset1 will contain the original good values at any points + which produced bad values after the above transformation - the other + points in pset1 will be bad. */ + nbad = 0; + if( astOK ) { + a = ptr1[ axis ]; + for( i = 0; i < nv; i++, a++ ){ + if( *a != AST__BAD ) { + vals[ i ] = *a; + *a = AST__BAD; + flags[ i ] = 1; + } else if( vals[ i ] != AST__BAD ) { + nbad++; + *a = vals[ i ]; + flags[ i ] = 0; + } else { + flags[ i ] = 1; + } + } + } + +/* We now try normalising any remaining bad positions using different + values for the other axis. This may result in some or all of the + remaining points being normalised succesfully. */ + for( itry = 0; itry < 10; itry++ ) { + +/* If the above transformation produced any bad values, try again with a + different value on the other axis. */ + if( astOK && nbad > 0 ) { + b = ptr1[ 1 - axis ]; + for( i = 0; i < nv; i++){ + *(b++) = refval + 0.1*( itry + 1 )*width; + } + +/* Transform to graphics coords and back to world coords. */ + (void) astTransform( map, pset1, 0, pset2 ); + (void) astTransform( map, pset2, 1, pset1 ); + +/* Copy any good positions back into the returned vals array. Count + remaining bad positions. */ + a = ptr1[ axis ]; + nbad = 0; + for( i = 0; i < nv; i++, a++ ){ + if( *a != AST__BAD ) { + vals[ i ] = *a; + flags[ i ] = 1; + *a = AST__BAD; + } else if( !flags[ i ] ) { + nbad++; + *a = vals[ i ]; + } + } + } + +/* If the above transformation produced any bad values, try again with a + different value on the other axis. */ + if( astOK && nbad > 0 ) { + b = ptr1[ 1 - axis ]; + for( i = 0; i < nv; i++){ + *(b++) = refval - 0.1*( itry + 1 )*width; + } + +/* Transform to graphics coords and back to world coords. */ + (void) astTransform( map, pset1, 0, pset2 ); + (void) astTransform( map, pset2, 1, pset1 ); + +/* Copy any good positions back into the returned vals array. Count + remaining bad positions. */ + a = ptr1[ axis ]; + nbad = 0; + for( i = 0; i < nv; i++, a++ ){ + if( *a != AST__BAD ) { + vals[ i ] = *a; + flags[ i ] = 1; + *a = AST__BAD; + } else if( !flags[ i ] ) { + nbad++; + *a = vals[ i ]; + } + } + } + } + +/* Free resources. */ + flags = (int *) astFree( flags ); + pset1 = astAnnul( pset1 ); + pset2 = astAnnul( pset2 ); + +} + +static void Opoly( AstPlot *this, int *status ){ +/* +* Name: +* Opoly + +* Purpose: +* Draws the current poly line. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Opoly( AstPlot *this, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function draws the current poly line, and empties the buffer. + +* Parameters: +* this +* Pointer to the Plot. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + int ipoly; /* Index of new polyline */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + +/* Check the global status. */ + if( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Draw the poly-line if needed. */ + if( Poly_n > 0 ) { + +/* Extend the global arrays that hold pointers to the polylines already + drawn. */ + ipoly = Poly_npoly++; + astBeginPM; + Poly_xp = astGrow( Poly_xp, Poly_npoly, sizeof(float*) ); + Poly_yp = astGrow( Poly_yp, Poly_npoly, sizeof(float*) ); + Poly_np = astGrow( Poly_np, Poly_npoly, sizeof(int) ); + astEndPM; + + if( astOK ) { + +/* Add pointers to the new polyline to the end of the above extended + arrays. */ + Poly_xp[ ipoly ] = Poly_x; + Poly_yp[ ipoly ] = Poly_y; + Poly_np[ ipoly ] = Poly_n; + +/* Indicate that the current polyline is now empty. */ + Poly_x = NULL; + Poly_y = NULL; + Poly_n = 0; + } + } +} + +static int Overlap( AstPlot *this, int mode, int esc, const char *text, float x, + float y, const char *just, float upx, float upy, + float **work, const char *method, const char *class, int *status ){ +/* +* Name: +* Overlap + +* Purpose: +* See if a major tick value label would overlap any of the previously +* drawn labels. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int Overlap( AstPlot *this, int mode, int esc, const char *text, float x, +* float y, const char *just, float upx, float upy, +* float **work, const char *method, const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* The operation of this function is determined by the "mode" parameter. + +* A record is kept of the bounding boxes enclosing all the displayed +* labels. If the bounding box of the new label defined by the given +* parameter values would overlap any of the old bounding boxes, 0 is +* returned. Otherwise 1 is returned and the bounding box for the new +* label is added to the list of old bounding boxes. + +* This function also updates the external variables Box_lbnd and +* Box_ubnd which hold the lower and upper bounds of the area enclosing +* all used labels. + +* Parameters: +* this +* A pointer to the Plot. +* mode +* - If -1, find the bounding box of the supplied label, add it +* to the list of stored bounding box, and return 1 if it overlaps +* any previously stored bounding boxes. +* - If -2, leave the bounding boxes unchanged and return the +* number of bounding boxes currently stored. No other action is taken +* and all other arguments are ignored. +* - Otherwise, reset the number of stored bounding boxes to the +* value of mode, and return the new number of bounding boxes. No +* action is taken if mode is less than zero or greater than the current +* number of stored boxes. No other action is taken and all other +* arguments are ignored. +* esc +* Should escape sequences in the text be interpreted? +* text +* A pointer to the label text string. +* x +* The graphics X coordinate of the label's reference point. +* y +* The graphics Y coordinate of the label's reference point. +* just +* A character string which specifies the location within the +* text string which is to be placed at the reference position +* given by x and y. The first character may be 'T' for "top", +* 'C' for "centre", or 'B' for "bottom", and specifies the +* vertical location of the reference position. The second +* character may be 'L' for "left", 'C' for "centre", or 'R' +* for "right", and specifies the horizontal location of the +* reference position. If the string has less than 2 characters +* then 'C' is used for the missing characters. +* upx +* The x component of the up-vector for the text. +* upy +* The y component of the up-vector for the text. +* work +* A pointer to a place at which to store a pointer to an array of +* floats holding the old bounding boxes. Memory to hold this array +* is allocated automatically within this function. The pointer to +* the array should be supplied as NULL on the first call to this +* function, and the array should be freed using astFree when no +* longer needed. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* See parameter "mode." + +* Notes: +* - Zero is returned if an error has occurred, or if this function +* should fail for any reason. + +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + int nbox = 0; /* Number of boxes stored in "work" */ + int ret; /* Does the new label overlap a previous label? */ + int i; /* Box index */ + float *cx; /* Pointer to next corner's X value */ + float *cy; /* Pointer to next corner's Y value */ + float xbn[ 4 ]; /* X coords at corners of new label's bounding box */ + float ybn[ 4 ]; /* Y coords at corners of new label's bounding box */ + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Initialise the returned value to indicate no overlap has been found. */ + ret = 0; + +/* Get the number of bounding boxes in the supplied work array. */ + if( work && *work ) { + nbox = (*work)[ 0 ]; + } else { + nbox = 0; + } + +/* If required, return the number of bounding boxes currently stored. */ + if( mode == -2 ) return nbox; + +/* If required, reset the number of bounding boxes currently stored, and + return the new number. */ + if( mode >= 0 ) { + if( mode < nbox && work && *work ) { + nbox = mode; + (*work)[ 0 ] = nbox; + } + return nbox; + } + +/* If no work array has been supplied, allocate one now with room for + 10 boxes. Each box requires 8 floats, 2 for each of the 4 corners. The + X graphics coordinates at the 4 corners are stored in the first 4 floats, + and the corresponding Y graphics coordinates in the second group of 4 + floats. */ + if( work && !(*work) ) { + *work = (float *) astMalloc( 81*sizeof(float) ); + if( astOK ) { + nbox = 0; + (*work)[ 0 ] = 0; + } + } + +/* Check the global status. */ + if( !astOK ) return ret; + +/* Get the bounds of the box containing the new label. */ + DrawText( this, 0, esc, text, x, y, just, upx, upy, + xbn, ybn, NULL, method, class, status ); + +/* If the bounding box was obtained succesfully... */ + if( astOK ) { + +/* Check for an overlap between the box and each of the previous boxes. */ + cx = *work + 1; + cy = cx + 4; + for( i = 0; i < nbox; i++ ){ + + if( BoxCheck( xbn, ybn, cx, cy, status ) ) { + ret = 1; + break; + } + +/* Increment the pointers to the next box. */ + cx += 8; + cy += 8; + + } + +/* If no overlap was found, add the new box to the list. */ + if( !ret ){ + *work = (float *) astGrow( (void *) *work, 8*nbox + 9, sizeof(float) ); + cx = *work + 1 + 8*nbox; + cy = cx + 4; + for( i = 0; i < 4; i++ ){ + cx[ i ] = xbn[ i ]; + cy[ i ] = ybn[ i ]; + } + (*work)[ 0 ]++; + +/* Extend the bounds of the global bounding box held externally to include + the new box. */ + for( i = 0; i < 4; i++ ){ + Box_lbnd[ 0 ] = astMIN( xbn[ i ], Box_lbnd[ 0 ] ); + Box_ubnd[ 0 ] = astMAX( xbn[ i ], Box_ubnd[ 0 ] ); + Box_lbnd[ 1 ] = astMIN( ybn[ i ], Box_lbnd[ 1 ] ); + Box_ubnd[ 1 ] = astMAX( ybn[ i ], Box_ubnd[ 1 ] ); + } + } + } + +/* If an error has occur, return a value of 0. */ + if( !astOK ) ret = 0; + +/* Return the answer. */ + return ret; + +} + +static void PlotLabels( AstPlot *this, int esc, AstFrame *frame, int axis, + LabelList *list, char *fmt, int nlab, float **box, + const char *method, const char *class, int *status ) { +/* +* +* Name: +* PlotLabels + +* Purpose: +* Draws the numerical labels which have been selected for display. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void PlotLabels( AstPlot *this, int esc, AstFrame *frame, int axis, +* LabelList *list, char *fmt, int nlab, float **box, +* const char *method, const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function displays the numerical labels supplied in the +* structure pointed to by "list". Overlapping labels are omitted, +* and redundant leading fields are removed from adjacent labels. +* Nothing is plotted if the NumLab attribute for the axis is false. + +* Parameters: +* this +* A pointer to the Plot. +* esc +* Interpret escape sequences in labels? +* frame +* A pointer to the current Frame of the Plot. +* axis +* The axis index (0 or 1). +* list +* A pointer to the LabelList structure holding information about +* the selected numerical labels. +* fmt +* A pointer to a null terminated string holding the format +* specification used to create the labels. +* nlab +* The number of labels described by "list". +* box +* A pointer to a place at which to store a pointer to an array of +* floats holding the bounding boxes of displayed labels. Memory to +* hold this array is allocated automatically within this function. +* The pointer to the array should be supplied as NULL on the first +* call to this function, and the array should be freed using astFree +* when no longer needed. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + LabelList *ll; /* Pointer to next label structure */ + LabelList *llhi; /* Pointer to higher neighbouring label structure */ + LabelList *lllo; /* Pointer to lower neighbouring label structure */ + char *text; /* Pointer to label text */ + const char *latext; /* Axis label at previous label */ + const char *texthi; /* Pointer to text abbreviated with higher neighbour */ + const char *textlo; /* Pointer to text abbreviated with lower neighbour */ + float tolx; /* Min allowed X interval between labels */ + float toly; /* Min allowed Y interval between labels */ + float xbn[ 4 ]; /* X coords at corners of new label's bounding box */ + float ybn[ 4 ]; /* Y coords at corners of new label's bounding box */ + int abb; /* Abbreviate leading fields? */ + int dp; /* Number of decimal places */ + int found; /* Non-zero digit found? */ + int hilen; /* Length of texthi */ + int i; /* Label index */ + int j; /* Label index offset */ + int jgap; /* Gap in index between rejected labels */ + int lab0; /* Index of middle label */ + int lolen; /* Length of textlo */ + int mxdp; /* Maximum number of decimal places */ + int nbox; /* The number of boinding boxes supplied */ + int nexti; /* Index of next label to retain */ + int nleft; /* No. of labels left */ + int nz; /* Number of trailing zeros in this label */ + int nzmax; /* Max. number of trailing zeros */ + int odd; /* DO we have a strange axis? */ + int off; /* Offset from central label */ + int olap; /* Any overlap found? */ + int prio; /* Current priority */ + int root; /* Index of unabbreviated label */ + int root_found; /* Has the root label been decided on? */ + int rootoff; /* Distance from middle to root label */ + int split; /* Indicates whether to split labels into 2 lines */ + +/* Return without action if an error has occurred, or there are no labels to + draw. */ + if( !astOK || nlab == 0 || !list || !astGetNumLab( this, axis ) ) return; + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + rootoff = 0; + +/* Get the number of bounding boxes describing the labels already drawn + (this will be non-zero only if this is the second axis to be labelled). */ + nbox = Overlap( this, -2, 0, NULL, 0.0, 0.0, NULL, 0.0, 0.0, box, method, + class, status ); + +/* Ensure the labels are sorted into increasing index order. */ + qsort( (void *) list, (size_t) nlab, sizeof(LabelList), Compare_LL ); + +/* Complex curves can have multiple edge crossings very close together. + This means that the same label can sometimes be included more than once + in the supplied list at the same (x,y) position. Purge duplicate labels + by setting their priority to -1. Initialise the priority of the remaining + labels to zero. */ + tolx = 0.02*fabs( this->xhi - this->xlo ); + toly = 0.02*fabs( this->yhi - this->ylo ); + ll = list; + ll->priority = 0; + ll->saved_prio = 0; + + for( i = 1; i < nlab; i++ ) { + ll++; + ll->priority = 0; + ll->saved_prio = 0; + for( j = 0; j < i; j++ ){ + if( !strcmp( ll->text, list[ j ].text ) ) { + if( fabs( ll->x - list[ j ].x ) < tolx && + fabs( ll->y - list[ j ].y ) < toly ) { + ll->priority = -1; + ll->saved_prio = -1; + break; + } + } + } + } + +/* Find the maximum number of decimal places in any label. */ + mxdp = 0; + ll = list - 1; + for( i = 0; i < nlab; i++ ) { + ll++; + FindDPTZ( frame, axis, fmt, ll->text, &dp, &nz, status ); + if( dp > mxdp ) mxdp = dp; + } + +/* Indicate that we do not yet know whether SplitValue should split labels + into two lines or not. */ + split = 0; + +/* Find the highest priority label (the "root" label). This label is + never abbreviated to remove leading fields, and is never omitted due to + overlaps with other labels. To find this label, each label is assigned a + priority equal to the number of trailing zeros in the label text. If the + text has fewer than the maximum number of decimal places, pretend the text + is padded with trailing zeros to bring the number of decimal places up to + the maximum. The root label is the highest priority label, giving + preference to labels which occur in the middle of the index order. At the + same time, initialize the abbreviated text for each label to be equal to + the unabbreviated text. */ + lab0 = nlab/2; + nzmax = -1; + ll = list - 1; + root = -1; + root_found = 0; + for( i = 0; i < nlab; i++ ) { + ll++; + if( ll->priority > -1 ) { + text = ll->text; + +/* Find the number of decimal places and the number of trailing zeros in + this label. Note if a non-zero digit was found in the label. */ + found = FindDPTZ( frame, axis, fmt, text, &dp, &nz, status ); + +/* Add on some extra trailing zeros to make the number of decimal places + up to the maximum value. */ + nz += mxdp - dp; + +/* Store the priority for this label. */ + ll->priority = nz; + ll->saved_prio = nz; + +/* Note the highest priority of any label. */ + if( nz > nzmax ) nzmax = nz; + +/* We will use this label as the root label if: + + - We have not already found the root label + + AND + + - It does not overlap any labels drawn for a previous axis + + AND + + - We do not currently have a candidate root label, or + - The priority for this label is higher than the priority of the current + root label, or + - The priority for this label is equal to the priority of the current + root label and this label is closer to the centre of the axis, or + - The label value is zero. */ + + if( root == -1 || + nz > list[ root ].priority || + ( nz == list[ root ].priority && abs( i - lab0 ) < rootoff ) || + !found ) { + + if( !root_found ) { + + if( axis == 0 || !Overlap( this, -1, esc, + SplitValue( this, ll->text, + axis, &split, status ), + (float) ll->x, (float) ll->y, + ll->just, (float) ll->upx, + (float) ll->upy, box, method, + class, status ) ) { + root = i; + rootoff = abs( i - lab0 ); + +/* If the label value was zero, we will use label as the root label, + regardless of the priorities of later labels. */ + if( !found ) root_found = 1; + } + +/* Reset the list of bounding boxes to exclude any box added above. */ + Overlap( this, nbox, esc, NULL, 0.0, 0.0, NULL, 0.0, 0.0, box, + method, class, status ); + + } + } + } + +/* Initialise the abbreviated text to be the same as the full text. */ + ll->atext = ll->text; + } + +/* If all the labels overlapped labels on a previous axis, arbitrarily + use the label with non-genative priority that is closest to the middle + as the root label (this should never happen but is included to avoid + segmentation violations occurring in error conditions such as the + txExt function being buggy and cuasing spurious overlaps). */ + if( root == -1 ) { + for( off = 0; off < (nlab-1)/2; off++ ) { + root = nlab/2 + off; + if( list[ root ].priority >= 0 ) break; + root = nlab/2 - off; + if( list[ root ].priority >= 0 ) break; + } + if( root == -1 ) { + astError( AST__PLFMT, "%s(%s): Cannot produce labels for axis %d.", + status, method, class, axis + 1 ); + root = nlab/2; + } + } + +/* Assign a priority higher than any other priority to the root label. */ + list[ root ].priority = nzmax + 1; + list[ root ].saved_prio = nzmax + 1; + +/* See if leading fields are to be abbreviated */ + abb = astGetAbbrev( this, axis ); + +/* The following process may have removed some labels which define the + missing fields in neighbouring abbreviated fields, so that the user + would not be able to tell what value the abbvreviated leading fields + should have. We therefore loop back and perform the abbreviation + process again, omitting the removed labels this time. Continue doing + this until no further labels are removed. */ + jgap = 1; + olap = 1; + odd = 0; + while( olap && !odd ) { + +/* We now attempt to abbreviate the remaining labels (i.e. those which + have not been rejected on an earlier pass through this loop). Labels + are abbreviated in order of their priority. Higher priority labels are + abbreviated first (except that the root label, which has the highest + priority, is never abbreviated). Each label is abbreviated by comparing + it with the nearest label with a higher priority. */ + +/* Loop through all the priority values, starting with the highest + priority (excluding the root label so that the root label is never + abbreviated), and working downwards to finish with zero priority. */ + prio = nzmax + 1; + while( prio-- > 0 ) { + +/* Look for labels which have the current priority. */ + ll = list - 1; + for( i = 0; i < nlab; i++ ) { + ll++; + if( ll->priority == prio ) { + +/* Find the closest label to this one on the high index side which has a + higher priority. */ + llhi = NULL; + for( j = i + 1; j < nlab; j++ ) { + if( list[ j ].priority > prio ) { + llhi = list + j; + break; + } + } + +/* If no higher priority neighbour was found on the high index side, + use the nearest label with the current priority on the high index side. */ + if( !llhi ) { + for( j = i + 1; j < nlab; j++ ) { + if( list[ j ].priority == prio ) { + llhi = list + j; + break; + } + } + } + +/* Find the closest label to this one on the low index side which has a + higher priority. */ + lllo = NULL; + for( j = i - 1; j >= 0; j-- ) { + if( list[ j ].priority > prio ) { + lllo = list + j; + break; + } + } + +/* If no higher priority neighbour was found on the low index side, + use the nearest label with the current priority on the low index side. */ + if( !lllo ) { + for( j = i - 1; j >= 0; j-- ) { + if( list[ j ].priority == prio ) { + lllo = list + j; + break; + } + } + } + +/* If we are not abbreviating, use the full text as the abbreviated text.*/ + if( !abb ) { + ll->atext = ll->text; + +/* Otherwise, if only one of these two neighbouring labels was found, we + abbreviate the current label by comparing it with the one found + neighbouring label. If they are identical, we use the last field as + the abbreviated text. */ + } else if( !lllo ) { + ll->atext = astAbbrev( frame, axis, fmt, llhi->text, + ll->text ); + + } else if( !llhi ) { + ll->atext = astAbbrev( frame, axis, fmt, lllo->text, + ll->text ); + +/* If two neighbouring labels were found, we abbreviate the current label + by comparing it with both neighbouring labels, and choosing the shorter + abbreviation. */ + } else { + textlo = abb ? astAbbrev( frame, axis, fmt, lllo->text, + ll->text ) : ll->text; + texthi = abb ? astAbbrev( frame, axis, fmt, llhi->text, + ll->text ) : ll->text; + + lolen = strlen( textlo ); + hilen = strlen( texthi ); + if( lolen > 0 && lolen < hilen ) { + ll->atext = textlo; + } else { + ll->atext = texthi; + } + } + +/* If the two fields are identical, the abbreviated text returned by + astAbbrev will be a null string. In this case, find the start of the + last field in the formatted value (using astAbbrev again), and use + that as the abbreviated text. */ + if( !(ll->atext)[0] ) { + ll->atext = astAbbrev( frame, axis, fmt, NULL, ll->text ); + } + } + } + } + +/* Find the bounding box of the root label and add it to the list of bounding + boxes. */ + nleft = 1; + ll = list + root; + olap = Overlap( this, -1, esc, + SplitValue( this, ll->atext, axis, &split, status ), + (float) ll->x, (float) ll->y, ll->just, (float) ll->upx, + (float) ll->upy, box, method, class, status ); + +/* Now look for labels which would overlap. First, check labels above the root + label. Do not count overlaps where the two abbreviated labels have the same text. */ + ll = list + root; + latext = ll->atext; + for( i = root + 1; i < nlab; i++ ) { + ll++; + if( ll->priority >= 0 ) { + if( strcmp( ll->atext, latext ) ) { + if( Overlap( this, -1, esc, + SplitValue( this, ll->atext, axis, &split, status ), + (float) ll->x, (float) ll->y, ll->just, + (float) ll->upx, (float) ll->upy, box, method, + class, status ) ){ + olap++; + } else { + nleft++; + } + } + latext = ll->atext; + } + } + +/* Now check the labels below the root label. */ + ll = list + root; + latext = ll->atext; + for( i = root - 1; i >= 0; i-- ) { + ll--; + if( ll->priority >= 0 ) { + if( strcmp( ll->atext, latext ) ) { + if( Overlap( this, -1, esc, + SplitValue( this, ll->atext, axis, &split, status ), + (float) ll->x, (float) ll->y, ll->just, + (float) ll->upx, (float) ll->upy, box, method, + class, status ) ){ + olap++; + } else { + nleft++; + } + } + latext = ll->atext; + } + } + +/* If only one overlap was found, and this is the second axis, ignore it + since it is probably caused by the crossing of the two axes. */ + if( axis == 1 && olap == 1 ) olap = 0; + +/* If we are now only plotting every 3rd label, or if there are less than + 3 labels left, and there are still overlapping labels, then we must have + a very odd axis (such as logarithmically spaced ticks on a linearly mapped + axis). In this case, we will re-instate the orignal label priorities and + then leave this loop so that we attempt to plot all labels. Also retain + original priorities if the axis is mapped logarithmically onto the + screen. */ + if( olap && ( jgap == 3 || nleft < 3 || astGetLogPlot( this, axis ) ) ){ + jgap = 0; + odd = 1; + } else { + odd = 0; + } + +/* If any labels overlapped, re-instate the priority of all previously + excluded labels (using the copy of the label's real priority stored in + "saved_prio"), and then remove labels (by setting their priorities + negative) to increase the gap between labels, and try again. */ + if( olap ) { + jgap++; + + nexti = root + jgap; + for( i = root + 1; i < nlab; i++ ) { + if( i == nexti ) { + nexti += jgap; + list[ i ].priority = list[ i ].saved_prio; + } else { + list[ i ].priority = -1; + } + } + + nexti = root - jgap; + for( i = root - 1; i >= 0; i-- ) { + if( i == nexti ) { + nexti -= jgap; + list[ i ].priority = list[ i ].saved_prio; + } else { + list[ i ].priority = -1; + } + } + +/* Reset the abbreviated text to be the full text. */ + for( i = 0; i < nlab - 1; i++ ) list[ i ].atext = list[ i ].text; + + } + +/* Rest the list of bounding boxes to exclude the boxes added above. */ + Overlap( this, nbox, esc, NULL, 0.0, 0.0, NULL, 0.0, 0.0, box, method, + class, status ); + } + +/* We can now draw the abbreviated labels (ignoring rejected labels). */ + ll = list-1; + for( i = 0; i < nlab; i++ ) { + ll++; + if( ll->priority >= 0 ) { + +/* Check that this label does not overlap any labels drawn for previous + axes (we know from the above processing that it will not overlap any + other label on the current axis). */ + if( !Overlap( this, -1, esc, + SplitValue( this, ll->atext, axis, &split, status ), + (float) ll->x, (float) ll->y, ll->just, (float) ll->upx, + (float) ll->upy, box, method, class, status ) ) { + +/* Draw the abbreviated label text, and get the bounds of the box containing + the new label, splitting long formatted values (such as produced by + TimeFrames) into two lines. */ + DrawText( this, 1, esc, + SplitValue( this, ll->atext, axis, &split, status ), + (float) ll->x, (float) ll->y, ll->just, (float) ll->upx, + (float) ll->upy, xbn, ybn, NULL, method, class, status ); + } + } + } +} + +static void PolyCurve( AstPlot *this, int npoint, int ncoord, int indim, + const double *in, int *status ){ +/* +*++ +* Name: +c astPolyCurve +f AST_POLYCURVE + +* Purpose: +* Draw a series of connected geodesic curves. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "plot.h" +c void astPolyCurve( AstPlot *this, int npoint, int ncoord, int indim, +c const double *in ) +f CALL AST_POLYCURVE( THIS, NPOINT, NCOORD, INDIM, IN, STATUS ) + +* Class Membership: +* Plot method. + +* Description: +c This function joins a series of points specified in the physical +c coordinate system of a Plot by drawing a sequence of geodesic +c curves. It is equivalent to making repeated use of the astCurve +c function (q.v.), except that astPolyCurve will generally be more +c efficient when drawing many geodesic curves end-to-end. A +c typical application of this might be in drawing contour lines. +f This routine joins a series of points specified in the physical +f coordinate system of a Plot by drawing a sequence of geodesic +f curves. It is equivalent to making repeated calls to the +f AST_CURVE routine (q.v.), except that AST_POLYCURVE will +f generally be more efficient when drawing many geodesic curves +f end-to-end. A typical application of this might be in drawing +f contour lines. +* +c As with astCurve, full account is taken of the Mapping between +c physical and graphical coordinate systems. This includes any +c discontinuities and clipping established using astClip. +f As with AST_CURVE, full account is taken of the Mapping between +f physical and graphical coordinate systems. This includes any +f discontinuities and clipping established using AST_CLIP. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +c npoint +f NPOINT = INTEGER (Given) +* The number of points between which geodesic curves are to be drawn. +c ncoord +f NCOORD = INTEGER (Given) +* The number of coordinates being supplied for each point (i.e. +* the number of axes in the current Frame of the Plot, as given +* by its Naxes attribute). +c indim +f INDIM = INTEGER (Given) +c The number of elements along the second dimension of the "in" +f The number of elements along the first dimension of the IN +* array (which contains the input coordinates). This value is +* required so that the coordinate values can be correctly +* located if they do not entirely fill this array. The value +c given should not be less than "npoint". +f given should not be less than NPOINT. +c in +f IN( INDIM, NCOORD ) = DOUBLE PRECISION (Given) +c The address of the first element in a 2-dimensional array of shape +c "[ncoord][indim]" giving the +c physical coordinates of the points which are to be joined in +c sequence by geodesic curves. These should be stored such that +c the value of coordinate number "coord" for point number +c "point" is found in element "in[coord][point]". +f A 2-dimensional array giving the physical coordinates of the +f points which are to be joined in sequence by geodesic +f curves. These should be stored such that the value of +f coordinate number COORD for input point number POINT is found +f in element IN(POINT,COORD). +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +* - No curve is drawn on either side of any point which has any +* coordinate equal to the value AST__BAD. +* - An error results if the base Frame of the Plot is not +* 2-dimensional. +* - An error also results if the transformation between the +* current and base Frames of the Plot is not defined (i.e. the +* Plot's TranInverse attribute is zero). +*-- +*/ +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + const char *class; /* Object class */ + const char *method; /* Current method */ + const double **in_ptr; /* Pointer to array of data pointers */ + double *finish; /* Pointer to array holding segment end position */ + double *start; /* Pointer to array holding segment start position */ + double d[ CRV_NPNT ]; /* Offsets to evenly spaced points along curve */ + double tol; /* Absolute tolerance value */ + double x[ CRV_NPNT ]; /* X coords at evenly spaced points along curve */ + double y[ CRV_NPNT ]; /* Y coords at evenly spaced points along curve */ + int coord; /* Loop counter for coordinates */ + int i; /* Loop count */ + int naxes; /* No. of Frame axes */ + int ok; /* Are all start and end coords good? */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Store the current method, and the class of the supplied object for use + in error messages.*/ + method = "astPolyCurve"; + class = astGetClass( this ); + +/* Check the base Frame of the Plot is 2-D. */ + naxes = astGetNin( this ); + if( naxes != 2 && astOK ){ + astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " + "Frame of the supplied %s is invalid - this number should " + "be 2.", status, method, class, naxes, class ); + } + +/* Initialise the bounding box for primatives produced by this call. */ + if( !Boxp_freeze ) { + Boxp_lbnd[ 0 ] = FLT_MAX; + Boxp_lbnd[ 1 ] = FLT_MAX; + Boxp_ubnd[ 0 ] = FLT_MIN; + Boxp_ubnd[ 1 ] = FLT_MIN; + } + +/* Check the current Frame of the Plot has ncoord axes. */ + naxes = astGetNout( this ); + if( naxes != ncoord && astOK ){ + astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the current " + "Frame of the supplied %s is invalid - this number should " + "be %d (possible programming error).", status, method, class, naxes, + class, ncoord ); + } + +/* Check the array dimension argument. */ + if ( astOK && ( indim < npoint ) ) { + astError( AST__DIMIN, "%s(%s): The array dimension value " + "(%d) is invalid.", status, method, class, indim ); + astError( AST__DIMIN, "This should not be less than the number of " + "points being drawn (%d).", status, npoint ); + } + +/* Indicate that the GRF module should re-calculate it's cached values + (in case the state of the graphics system has changed since the last + thing was drawn). */ + RESET_GRF; + +/* Allocate memory to hold the array of data pointers, the start position, + and the end position. */ + if ( astOK ) { + in_ptr = (const double **) astMalloc( sizeof( const double * ) * + (size_t) ncoord ); + start = (double *) astMalloc( sizeof( double ) * (size_t) ncoord ); + finish = (double *) astMalloc( sizeof( double ) * (size_t) ncoord ); + +/* Set up externals used to communicate with the Map3 function... + The number of axes in the physical coordinate system (i.e. the current + Frame). */ + Map3_ncoord = ncoord; + +/* A pointer to the Plot, the Current Frame, and and Mapping. */ + Map3_plot = this; + Map3_frame = astGetFrame( this, AST__CURRENT ); + Map3_map = astGetMapping( this, AST__BASE, AST__CURRENT ); + +/* Convert the tolerance from relative to absolute graphics coordinates. */ + tol = astGetTol( this )*astMAX( this->xhi - this->xlo, + this->yhi - this->ylo ); + +/* Ensure the globals holding the scaling from graphics coords to equally + scaled coords are available. */ + GScales( this, NULL, NULL, method, class, status ); + +/* Now set up the external variables used by the Crv and CrvLine function. */ + Crv_scerr = ( astGetLogPlot( this, 0 ) || + astGetLogPlot( this, 1 ) ) ? 100.0 : 1.5; + Crv_tol = tol; + Crv_limit = 0.5*tol*tol; + Crv_map = Map3; + Crv_ink = 1; + Crv_xlo = this->xlo; + Crv_xhi = this->xhi; + Crv_ylo = this->ylo; + Crv_yhi = this->yhi; + Crv_clip = astGetClip( this ) & 1; + +/* Set up a list of points spread evenly over each curve segment. */ + for( i = 0; i < CRV_NPNT; i++ ){ + d[ i ] = ( (double) i)/( (double) CRV_NSEG ); + } + +/* Initialise the data pointers to locate the coordinate data in + the "in" array. */ + if ( astOK ) { + for ( coord = 0; coord < ncoord; coord++ ) { + in_ptr[ coord ] = in + coord * indim; + } + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + astGrfAttrs( this, AST__CURVE_ID, 1, GRF__LINE, method, class ); + +/* Loop round each curve segment. */ + for( i = 1 ; i < npoint; i++ ) { + +/* Store the start position and check it for bad values. Increment the + pointers to the next position on each axis, so that they refer to the + finish point of the current curve segment. */ + ok = 1; + for( coord = 0; coord < ncoord; coord++ ) { + if( *( in_ptr[coord] ) == AST__BAD ){ + ok = 0; + } else { + start[ coord ] = *( in_ptr[coord] ); + } + ( in_ptr[coord] )++; + } + +/* Store the end position and check it for bad values. Do not increment + the axis pointers. This means that they will refer to the start position + of the next curve segment on the next pass through this loop. */ + for( coord = 0; coord < ncoord; coord++ ) { + if( *( in_ptr[coord] ) == AST__BAD ){ + ok = 0; + } else { + finish[ coord ] = *( in_ptr[coord] ); + } + } + +/* Pass on to the next curve segment if either the start or finish position + was bad. */ + if( ok ) { + +/* Set up the remaining externals used to communicate with the Map3 + function... */ + +/* The physical coordinates at the start of the curve. */ + Map3_origin = start; + +/* The physical coordinates at the end of the curve. */ + Map3_end = finish; + +/* The scale factor to convert "dist" values into physical offset values. */ + Map3_scale = astDistance( Map3_frame, start, finish ); + +/* Now set up the remaining external variables used by the Crv and CrvLine + function. */ + Crv_ux0 = AST__BAD; + Crv_out = 1; + Crv_xbrk = Curve_data.xbrk; + Crv_ybrk = Curve_data.ybrk; + Crv_vxbrk = Curve_data.vxbrk; + Crv_vybrk = Curve_data.vybrk; + +/* Map the evenly spread distances between "start" and "finish" into graphics + coordinates. */ + Map3( CRV_NPNT, d, x, y, method, class, status GLOBALS_NAME ); + +/* Use Crv and Map3 to draw the curve segment. */ + Crv( this, d, x, y, 0, NULL, NULL, method, class, status ); + +/* If no part of the curve could be drawn, set the number of breaks and the + length of the drawn curve to zero. */ + if( Crv_out ) { + Crv_nbrk = 0; + Crv_len = 0.0F; + +/* Otherwise, add an extra break to the returned structure at the position of + the last point to be plotted. */ + } else { + Crv_nbrk++; + if( Crv_nbrk > AST__PLOT_CRV_MXBRK ){ + astError( AST__CVBRK, "%s(%s): Number of breaks in curve " + "exceeds %d.", status, method, class, AST__PLOT_CRV_MXBRK ); + } else { + *(Crv_xbrk++) = (float) Crv_xl; + *(Crv_ybrk++) = (float) Crv_yl; + *(Crv_vxbrk++) = (float) -Crv_vxl; + *(Crv_vybrk++) = (float) -Crv_vyl; + } + } + +/* Store extra information about the curve in the returned structure, and + purge any zero length sections. */ + Curve_data.length = Crv_len; + Curve_data.out = Crv_out; + Curve_data.nbrk = Crv_nbrk; + PurgeCdata( &Curve_data, status ); + } + } + +/* End the last poly line. */ + Opoly( this, status ); + +/* Tidy up the static data used by Map3. */ + Map3( 0, NULL, NULL, NULL, method, class, status GLOBALS_NAME ); + +/* Ensure all lines are flushed to the graphics system. */ + Fpoly( this, method, class, status ); + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, AST__CURVE_ID, 0, GRF__LINE, method, class ); + } + +/* Annul the Frame and Mapping. */ + Map3_frame = astAnnul( Map3_frame ); + Map3_map = astAnnul( Map3_map ); + +/* Free the memory used for the data pointers, and start and end positions. */ + in_ptr = (const double **) astFree( (void *) in_ptr ); + start = (double *) astFree( (void *) start ); + finish = (double *) astFree( (void *) finish ); + } +} + +static int PopGat( AstPlot *this, float *rise, const char *method, + const char *class, int *status ) { +/* +* Name: +* PopGat + +* Purpose: +* Pop current graphical attributes for text from a stack. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int PopGat( AstPlot *this, float *rise, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function restores the current graphical attributes for text +* from the values on a stack. Current attributes are left unchanged if +* the stack is empty. + +* Parameters: +* this +* Pointer to the Plot. +* rise +* Pointer to a location at which to return thhe height of the baseline +* above the normal baseline, expressed as a percentage of the normal +* character height. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Returns zero if the stack is empty, and 1 otherwise. + +*/ + +/* Local Variables: */ + AstGat *gat; + int result; + +/* Initialise */ + result = 0; + +/* Check inherited status */ + if( !astOK ) return result; + +/* Check there is at least one AstGat structure on the stack. */ + if( this->ngat ) { + +/* Decrement the number of entries in the stack, and get a pointer to the + AstGat structure. Nullify the pointer on the stack. */ + gat = (this->gat)[ --(this->ngat) ]; + (this->gat)[ this->ngat ] = NULL; + +/* Restore the values in the AstGat structure */ + *rise = gat->rise; + GAttr( this, GRF__SIZE, gat->size, NULL, GRF__TEXT, method, class, status ); + GAttr( this, GRF__WIDTH, gat->width, NULL, GRF__TEXT, method, class, status ); + GAttr( this, GRF__COLOUR, gat->col, NULL, GRF__TEXT, method, class, status ); + GAttr( this, GRF__FONT, gat->font, NULL, GRF__TEXT, method, class, status ); + GAttr( this, GRF__STYLE, gat->style, NULL, GRF__TEXT, method, class, status ); + +/* Free the AstGat structure. */ + gat = astFree( gat ); + +/* Indicate success.*/ + result = 1; + } + +/* Return the result. */ + return result; + +} + +static void PurgeCdata( AstPlotCurveData *cdata, int *status ){ +/* +* +* Name: +* AstPlotCurveData + +* Purpose: +* Remove any zero length sections from the description of a curve. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void PurgeCdata( AstPlotCurveData *cdata ) + +* Class Membership: +* Plot member function. + +* Description: +* This function removes any zero length sections from the supplied +* AstPlotCurveData struture, which describes a multi-section curve. + +* Parameters: +* cdata +* A pointer to the structure containing information about the +* breaks in a curve. + +*/ + +/* Local Variables: */ + int brk; /*Break index */ + int i; /*Break index */ + +/* Check the global error status. */ + if ( !astOK || !cdata ) return; + +/* Loop round all breaks. */ + brk = 0; + while( brk < cdata->nbrk ) { + +/* If this break and the next one are co-incident, remove both breaks. */ + if( cdata->xbrk[ brk ] == cdata->xbrk[ brk + 1 ] && + cdata->ybrk[ brk ] == cdata->ybrk[ brk + 1 ] ) { + +/* Shuffle down the higher elements of all the arrays in the curve data. */ + for( i = brk + 2; i < cdata->nbrk; i++ ){ + cdata->xbrk[ i - 2 ] = cdata->xbrk[ i ]; + cdata->ybrk[ i - 2 ] = cdata->ybrk[ i ]; + cdata->vxbrk[ i - 2 ] = cdata->vxbrk[ i ]; + cdata->vybrk[ i - 2 ] = cdata->vybrk[ i ]; + } + +/* Decrement the number of breaks in the curve data. */ + cdata->nbrk -= 2; + +/* If the section is not zero length, move on to the next pair of breaks. */ + } else { + brk += 2; + } + } +} + +static void PushGat( AstPlot *this, float rise, const char *method, + const char *class, int *status ) { +/* +* Name: +* PushGat + +* Purpose: +* Push current graphical attributes for text onto a stack. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void PushGat( AstPlot *this, float rise, const char *method, +* const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function stores the current graphical attributes for text +* on a stack. + +* Parameters: +* this +* Pointer to the Plot. +* rise +* The height of the baseline above the normal baseline, expressed +* as a percentage of the normal character height. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstGat *new_gat; + +/* Check inherited status */ + if( !astOK ) return; + +/* Allocate memory for a new AstGat structure to store the graphical + attributes. */ + new_gat = astMalloc( sizeof( AstGat ) ); + if( astOK ) { + +/* Store the height of the current baseline above the normal baseline, + expressed as a percentage of a normal character height. */ + new_gat->rise = rise; + +/* Store the current graphical attribute values. */ + GAttr( this, GRF__SIZE, AST__BAD, &(new_gat->size), GRF__TEXT, method, class, status ); + GAttr( this, GRF__WIDTH, AST__BAD, &(new_gat->width), GRF__TEXT, method, class, status ); + GAttr( this, GRF__FONT, AST__BAD, &(new_gat->font), GRF__TEXT, method, class, status ); + GAttr( this, GRF__STYLE, AST__BAD, &(new_gat->style), GRF__TEXT, method, class, status ); + GAttr( this, GRF__COLOUR, AST__BAD, &(new_gat->col), GRF__TEXT, method, class, status ); + +/* Increment the number of AstGat structures on the stack.*/ + this->ngat++; + +/* Extend the array of AstGat pointers in the Plot structure so that there + is room for the new one. */ + this->gat = (AstGat **) astGrow( this->gat, this->ngat, sizeof( AstGat * ) ); + if( astOK ) { + +/* Store the new pointer. */ + (this->gat)[ this->ngat - 1 ] = new_gat; + + } + } +} + +static void RegionOutline( AstPlot *this, AstRegion *region, int *status ){ +/* +*++ +* Name: +c astRegionOutline +f AST_RegionOutline + +* Purpose: +* Draw the outline of an AST Region. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "plot.h" +c void astRegionOutline( AstPlot *this, AstRegion *region ) +f CALL AST_REGIONOUTLINE( THIS, REGION, STATUS ) + +* Class Membership: +* Plot method. + +* Description: +* This function draws an outline around the supplied AST Region object. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +c region +f REGION = INTEGER (Given) +* Pointer to the Region. +f STATUS = INTEGER (Given and Returned) +f The global status. + +*-- +*/ +/* Local Variables: */ + AstFrameSet *fs; + AstMapping *map; + const char *class; + const char *method; + int ibase; + int icurr; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Store the current method, and the class of the supplied object for use + in error messages.*/ + method = "astRegionOutline"; + class = astGetClass( this ); + +/* Save the base Frame index within the Plot, since astConvert will + change it. */ + ibase = astGetBase( this ); + +/* Get the FrameSet that converts from the current Frame of the Plot, to the + Frame represented by the Region. Check a conversion was found. */ + fs = astConvert( this, region, " " ); + +/* Re-instate the original base Frame. */ + astSetBase( this, ibase ); + +/* Report an error if the Region could not be mapped into the current + Frame of the Plot. */ + if( !fs ) { + if( astOK ) { + astError( AST__NOCNV, "%s(%s): Cannot find a mapping from the " + "%d-dimensional Plot coordinate system (%s) to the " + "%d-dimensional Region coordinate system (%s).", status, + method, class, astGetNout( this ), astGetTitle( this ), + astGetNout( region ), astGetTitle( region ) ); + } + +/* If a transformation from Plot to Region was found... */ + } else { + +/* Add the Region as a new Frame into the Plot, connecting it to the + current Frame using the FrameSet found above. It becomes the new current + Frame. First record the index of the original current Frame since + astAddFrame will modify the FrameSet to use a different current Frame. */ + icurr = astGetCurrent( this ); + map = astGetMapping( fs, AST__BASE, AST__CURRENT ); + astAddFrame( this, icurr, map, region ); + +/* Draw the outline of the Region (now the current Frame in the Plot). */ + astBorder( this ); + +/* Tidy up by removing the Region (i.e. the current Frame) from the Plot and + re-instating the original current Frame. */ + astRemoveFrame( this, AST__CURRENT ); + astSetCurrent( this, icurr ); + +/* Free resources. */ + map = astAnnul( map ); + fs = astAnnul( fs ); + } +} + +static void RemoveFrame( AstFrameSet *this_fset, int iframe, int *status ) { +/* +* Name: +* RemoveFrame + +* Purpose: +* Remove a Frame from a Plot. + +* Type: +* Public virtual function. + +* Synopsis: +* #include "plot.h" +* void RemoveFrame( AstFrameSet *this_fset, int iframe, int *status ) + +* Class Membership: +* Plot member function (over-rides the astRemoveFrame public +* method inherited from the FrameSet class). + +* Description: +* This function removes a Frame from a Plot. All other Frames +* in the Plot have their indices re-numbered from one (if +* necessary), but are otherwise unchanged. +* +* If the index of the clipping Frame is changed, the index value +* stored in the Plot is updated. If the clipping Frame itself is +* removed, all clipping information is removed from the Plot. + +* Parameters: +* this_fset +* Pointer to the FrameSet component of the Plot. +* iframe +* The index within the Plot of the Frame to be removed. +* This value should lie in the range from 1 to the number of +* Frames in the Plot (as given by its Nframe attribute). +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstPlot *this; /* Pointer to Plot structure */ + int ifrm; /* Validated frame index */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the Plot structure. */ + this = (AstPlot *) this_fset; + +/* Validate the frame index. */ + ifrm = astValidateFrameIndex( this_fset, iframe, "astRemoveFrame" ); + +/* Invoke the parent astRemoveFrame method to remove the Frame. */ + (*parent_removeframe)( this_fset, iframe, status ); + +/* If the index of the removed Frame is smaller than the clipping Frame + index, then decrement the clipping Frame index so that the same Frame + will be used in future. */ + if( astOK ){ + if( ifrm < this->clip_frame ){ + (this->clip_frame)--; + +/* If the clipping fgrame itself has been removed, indicate that no + clipping should nbow be performed. */ + } else if( ifrm == this->clip_frame ){ + astClip( this, AST__NOFRAME, NULL, NULL ); + } + } +} + +static void RightVector( AstPlot *this, float *ux, float *uy, float *rx, + float *ry, const char *method, const char *class, int *status ){ +/* +* Name: +* RightVector + +* Purpose: +* Return a vector in the direction of the base line of normal text. + +* Synopsis: +* #include "plot.h" +* void RightVector( AstPlot *this, float *ux, float *uy, float *rx, +* float *ry, const char *method, const char *class, int *status ) + +* Description: +* This function returns a vector which points from left to right along +* the text baseline, taking account of any difference in the scales of +* the x and y axes. It also scales the supplied up vector so that it has +* a length equal to the height of normal text, and scales the returned +* right vector to have the same length (on the screen) as the up vector. + +* Parameters: +* this +* The plot. +* ux +* Pointer to a float holding the x component of the up-vector for the +* text, in graphics coords. Scaled on exit so that the up vector has +* length equal to the height of normal text. +* uy +* Pointer to a float holding the y component of the up-vector for the +* text, in graphics coords. Scaled on exit so that the up vector has +* length equal to the height of normal text. +* rx +* Pointer to a double in which will be put the x component of a +* vector parallel to the baseline of normal text. +* ry +* Pointer to a double in which will be put the y component of a +* vector parallel to the baseline of normal text. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + + +/* Local Variables: */ + float alpha; /* Scale factor for X axis */ + float beta; /* Scale factor for Y axis */ + float chv; + float chh; + float l; /* Normalisation constant */ + float a; + float b; + float nl; /* Character height in standard coordinates */ + +/* Check inherited status */ + if( !astOK ) return; + +/* Find the scale factors for the two axes which scale graphics coordinates + into a "standard" coordinate system in which: 1) the axes have equal scale + in terms of (for instance) millimetres per unit distance, 2) X values + increase from left to right, 3) Y values increase from bottom to top. */ + GScales( this, &alpha, &beta, method, class, status ); + +/* Convert the up-vector into "standard" system in which the axes have + equal scales, and increase left-to-right, bottom-to-top. */ + *ux *= alpha; + *uy *= beta; + +/* Normalise this up-vector. */ + l = sqrt( (*ux)*(*ux) + (*uy)*(*uy) ); + if( l <= 0.0 ) { + *ux = 0.0; + *uy = 1.0; + } else { + *ux /= l; + *uy /= l; + } + +/* Find the height in "standard" coordinates of "normal" text draw with the + requested up-vector. */ + GQch( this, &chv, &chh, method, class, status ); + a = (*ux)/(chv*alpha); + b = (*uy)/(chh*beta); + nl = 1.0/sqrt( a*a + b*b ); + +/* Scale the up-vector so that is has length equal to the height of "normal" + text with the specified up-vector. */ + *ux *= nl; + *uy *= nl; + +/* Get the vector along the base-line of the text, by rotating the + up-vector by 90 degrees clockwise. */ + *rx = *uy; + *ry = -*ux; + +/* Convert both vectors back from standard coords to normal world coords */ + *ux /= alpha; + *uy /= beta; + *rx /= alpha; + *ry /= beta; + +} + +static void SaveTick( AstPlot *this, int axis, double gx, double gy, + int major, int *status ){ +/* +* Name: +* SaveTick + +* Purpose: +* Save info about a drawn tick in the Plot structure. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void SaveTick( AstPlot *this, int axis, double gx, double gy, +* int major, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function stores the start position and type of each drawn +* tick in the given Plot. + +* Parameters: +* this +* Pointer to the Plot. +* axis +* The zero-based axis index to which the tick refers. If a +* negative value is specified then all information about drawn ticks +* curently stored in the Plot is erased. +* gx +* The graphics X position at the start of the tick mark. +* gy +* The graphics Y position at the start of the tick mark. +* major +* Non-zero if the tick mark is a major tick. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + int i; + int *count; + double *tickgx; + double *tickgy; + +/* Free the tick info in the supplied Plot if required. Do this before + checking the error status. */ + if( axis < 0 ) { + for( i = 0; i < 3; i++ ) { + this->majtickgx[ i ] = astFree( this->majtickgx[ i ] ); + this->majtickgy[ i ] = astFree( this->majtickgy[ i ] ); + this->mintickgx[ i ] = astFree( this->mintickgx[ i ] ); + this->mintickgy[ i ] = astFree( this->mintickgy[ i ] ); + this->mintickcount[ i ] = 0; + this->majtickcount[ i ] = 0; + } + return; + } + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get pointers to the arrays to use, and ensure the arrays are big + enough to hold the new tick. */ + if( major ) { + count = this->majtickcount + axis; + tickgx = this->majtickgx[ axis ]; + tickgy = this->majtickgy[ axis ]; + } else { + count = this->mintickcount + axis; + tickgx = this->mintickgx[ axis ]; + tickgy = this->mintickgy[ axis ]; + } + +/* Ensure the arrays are big enough to hold the new tick. */ + i = *count; + tickgx = astGrow( tickgx, i + 1, sizeof( double ) ); + tickgy = astGrow( tickgy, i + 1, sizeof( double ) ); + +/* If memory was allocated succesfully, store the new tick information in + the expanded arrays. */ + if( astOK ) { + tickgx[ i ] = gx; + tickgy[ i ] = gy; + *count = i + 1; + +/* Store the potentially updated array pointers. */ + if( major ) { + this->majtickgx[ axis ] = tickgx; + this->majtickgy[ axis ] = tickgy; + } else { + this->mintickgx[ axis ] = tickgx; + this->mintickgy[ axis ] = tickgy; + } + } +} + +static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { +/* +* Name: +* SetAttrib + +* Purpose: +* Set an attribute value for a Plot. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void SetAttrib( AstObject *this, const char *setting, int *status ) + +* Class Membership: +* Plot member function (over-rides the astSetAttrib protected +* method inherited from the FrameSet class). + +* Description: +* This function assigns an attribute value for a Plot, the +* attribute and its value being specified by means of a string of +* the form: +* +* "attribute= value " +* +* Here, "attribute" specifies the attribute name and should be in +* lower case with no white space present. The value to the right +* of the "=" should be a suitable textual representation of the +* value to be assigned and this will be interpreted according to +* the attribute's data type. White space surrounding the value is +* only significant for string attributes. + +* Parameters: +* this +* Pointer to the Plot. +* setting +* Pointer to a null terminated string specifying the new attribute +* value. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + AstPlot *this; /* Pointer to the Plot structure */ + char label[21]; /* Graphics item label */ + const char *class; /* Pointer to class string */ + double dval; /* Double attribute value */ + int axis; /* Index for the axis */ + int edge; /* Index of edge within list */ + int id1; /* Plot object id */ + int id2; /* Plot object id */ + int id; /* Plot object id */ + int ival; /* Int attribute value */ + int len; /* Length of setting string */ + int nax; /* Number of graphics frame axes */ + int nc; /* Number of characters read by astSscanf */ + int id3; /* Third genuine identifier */ + int nid; /* Number of genuine attributes */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the Plot structure. */ + this = (AstPlot *) this_object; + +/* Get the number of base Frame axis (2 for a Plot, 3 for a Plot3D). */ + nax = astGetNin( this ); + +/* Obtain the length of the setting string. */ + len = (int) strlen( setting ); + +/* Test for each recognised attribute in turn, using "astSscanf" to parse + the setting string and extract the attribute value (or an offset to + it in the case of string values). In each case, use the value set + in "nc" to check that the entire string was matched. Once a value + has been obtained, use the appropriate method to set it. */ + +/* Tol. */ +/* ---- */ + if ( nc = 0, + ( 1 == astSscanf( setting, "tol= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + astSetTol( this, dval ); + +/* Grid. */ +/* ----- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "grid= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetGrid( this, ival ); + +/* TickAll. */ +/* -------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "tickall= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetTickAll( this, ival ); + +/* ForceExterior */ +/* ------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "forceexterior= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetForceExterior( this, ival ); + +/* Invisible. */ +/* ---------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "invisible= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetInvisible( this, ival ); + +/* Border. */ +/* ------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "border= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetBorder( this, ival ); + +/* ClipOp. */ +/* ------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "clipop= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetClipOp( this, ival ); + +/* Clip. */ +/* ----- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "clip= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetClip( this, ival ); + +/* Grf. */ +/* ---- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "grf= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetGrf( this, ival ); + +/* DrawTitle. */ +/* ---------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "drawtitle= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetDrawTitle( this, ival ); + +/* DrawAxes. */ +/* --------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "drawaxes= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetDrawAxes( this, axis, ival ); + +/* DrawAxes(axis). */ +/* --------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "drawaxes(%d)= %d %n", + &axis, &ival, &nc ) ) + && ( nc >= len ) ) { + astSetDrawAxes( this, axis - 1, ival ); + +/* Abbrev. */ +/* ------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "abbrev= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetAbbrev( this, axis, ival ); + +/* Abbrev(axis). */ +/* --------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "abbrev(%d)= %d %n", + &axis, &ival, &nc ) ) + && ( nc >= len ) ) { + astSetAbbrev( this, axis - 1, ival ); + +/* Escape. */ +/* ------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "escape= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetEscape( this, ival ); + +/* Edge(axis). */ +/* ----------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "edge(%d)= %n%*s %n", &axis, &ival, &nc ) ) + && ( nc >= len ) ) { + edge = FullForm( "left right top bottom", setting + ival, setting, + "astSet", astGetClass( this ), status ); + if( edge == 0 ) { + astSetEdge( this, axis - 1, LEFT ); + } else if( edge == 1 ) { + astSetEdge( this, axis - 1, RIGHT ); + } else if( edge == 2 ) { + astSetEdge( this, axis - 1, TOP ); + } else if( edge == 3 ) { + astSetEdge( this, axis - 1, BOTTOM ); + } + +/* LabelAt (axis). */ +/* --------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "labelat(%d)= %lg %n", + &axis, &dval, &nc ) ) + && ( nc >= len ) ) { + astSetLabelAt( this, axis - 1, dval ); + +/* Centre(axis). */ +/* ------------ */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "centre(%d)= %lg %n", + &axis, &dval, &nc ) ) + && ( nc >= len ) ) { + astSetCentre( this, axis - 1, dval ); + +/* Gap. */ +/* ---- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "gap= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetGap( this, axis, dval ); + +/* Gap(axis). */ +/* ---------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "gap(%d)= %lg %n", + &axis, &dval, &nc ) ) + && ( nc >= len ) ) { + astSetGap( this, axis - 1, dval ); + +/* LogGap. */ +/* ---- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "loggap= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetLogGap( this, axis, dval ); + +/* LogGap(axis). */ +/* ---------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "loggap(%d)= %lg %n", + &axis, &dval, &nc ) ) + && ( nc >= len ) ) { + astSetLogGap( this, axis - 1, dval ); + +/* NumLabGap. */ +/* -------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "numlabgap= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetNumLabGap( this, axis, dval ); + +/* NumLabGap(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "numlabgap(%d)= %lg %n", + &axis, &dval, &nc ) ) + && ( nc >= len ) ) { + astSetNumLabGap( this, axis - 1, dval ); + +/* TextLabGap. */ +/* -------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "textlabgap= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetTextLabGap( this, axis, dval ); + +/* TextLabGap(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "textlabgap(%d)= %lg %n", + &axis, &dval, &nc ) ) + && ( nc >= len ) ) { + astSetTextLabGap( this, axis - 1, dval ); + +/* LabelUp. */ +/* -------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "labelup= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetLabelUp( this, axis, ival ); + +/* LabelUp(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "labelup(%d)= %d %n", + &axis, &ival, &nc ) ) + && ( nc >= len ) ) { + astSetLabelUp( this, axis - 1, ival ); + +/* LogPlot. */ +/* -------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "logplot= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetLogPlot( this, axis, ival ); + +/* LogPlot(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "logplot(%d)= %d %n", + &axis, &ival, &nc ) ) + && ( nc >= len ) ) { + astSetLogPlot( this, axis - 1, ival ); + +/* LogTicks. */ +/* -------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "logticks= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetLogTicks( this, axis, ival ); + +/* LogTicks(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "logticks(%d)= %d %n", + &axis, &ival, &nc ) ) + && ( nc >= len ) ) { + astSetLogTicks( this, axis - 1, ival ); + +/* LogLabel. */ +/* -------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "loglabel= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetLogLabel( this, axis, ival ); + +/* LogLabel(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "loglabel(%d)= %d %n", + &axis, &ival, &nc ) ) + && ( nc >= len ) ) { + astSetLogLabel( this, axis - 1, ival ); + +/* NumLab. */ +/* -------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "numlab= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetNumLab( this, axis, ival ); + +/* NumLab(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "numlab(%d)= %d %n", + &axis, &ival, &nc ) ) + && ( nc >= len ) ) { + astSetNumLab( this, axis - 1, ival ); + +/* MinTick. */ +/* -------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "mintick= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetMinTick( this, axis, ival ); + +/* MinTick(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "mintick(%d)= %d %n", + &axis, &ival, &nc ) ) + && ( nc >= len ) ) { + astSetMinTick( this, axis - 1, ival ); + +/* TextLab. */ +/* ---------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "textlab= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetTextLab( this, axis, ival ); + +/* TextLab(axis). */ +/* ---------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "textlab(%d)= %d %n", + &axis, &ival, &nc ) ) + && ( nc >= len ) ) { + astSetTextLab( this, axis - 1, ival ); + +/* LabelUnits. */ +/* --------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "labelunits= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetLabelUnits( this, axis, ival ); + +/* LabelUnits(axis). */ +/* ---------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "labelunits(%d)= %d %n", + &axis, &ival, &nc ) ) + && ( nc >= len ) ) { + astSetLabelUnits( this, axis - 1, ival ); + +/* Style. */ +/* ------ */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "style= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( id = 0; id < AST__NPID; id++ ) astSetStyle( this, id, ival ); + +/* Style(label). */ +/* ------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "style(%20[^()])= %d %n", + label, &ival, &nc ) ) + && ( nc >= len ) ) { + class = astGetClass( this ); + + nid = IdFind( FullForm( GrfLabels, label, "Style", "astSet", class, status ), + nax, &id1, &id2, &id3, status ); + astSetStyle( this, id1, ival ); + if( nid > 1 ) astSetStyle( this, id2, ival ); + if( nid > 2 ) astSetStyle( this, id3, ival ); + +/* Font. */ +/* ----- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "font= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( id = 0; id < AST__NPID; id++ ) astSetFont( this, id, ival ); + +/* Font(label). */ +/* ------------ */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "font(%20[^()])= %d %n", + label, &ival, &nc ) ) + && ( nc >= len ) ) { + class = astGetClass( this ); + + nid = IdFind( FullForm( GrfLabels, label, "Font", "astSet", class, status ), + nax, &id1, &id2, &id3, status ); + astSetFont( this, id1, ival ); + if( nid > 1 ) astSetFont( this, id2, ival ); + if( nid > 2 ) astSetFont( this, id3, ival ); + +/* Colour. */ +/* ------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "colour= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( id = 0; id < AST__NPID; id++ ) astSetColour( this, id, ival ); + +/* Colour(label). */ +/* -------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "colour(%20[^()])= %d %n", + label, &ival, &nc ) ) + && ( nc >= len ) ) { + class = astGetClass( this ); + + nid = IdFind( FullForm( GrfLabels, label, "Colour", "astSet", class, status ), + nax, &id1, &id2, &id3, status ); + astSetColour( this, id1, ival ); + if( nid > 1 ) astSetColour( this, id2, ival ); + if( nid > 2 ) astSetColour( this, id3, ival ); + +/* Color. */ +/* ------ */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "color= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + for( id = 0; id < AST__NPID; id++ ) astSetColour( this, id, ival ); + +/* Color(label). */ +/* ------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "color(%20[^()])= %d %n", + label, &ival, &nc ) ) + && ( nc >= len ) ) { + class = astGetClass( this ); + + nid = IdFind( FullForm( GrfLabels, label, "Color", "astSet", class, status ), + nax, &id1, &id2, &id3, status ); + astSetColour( this, id1, ival ); + if( nid > 1 ) astSetColour( this, id2, ival ); + if( nid > 2 ) astSetColour( this, id3, ival ); + +/* Width. */ +/* ------ */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "width= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + for( id = 0; id < AST__NPID; id++ ) astSetWidth( this, id, dval ); + +/* Width(label). */ +/* ------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "width(%20[^()])= %lg %n", + label, &dval, &nc ) ) + && ( nc >= len ) ) { + class = astGetClass( this ); + + nid = IdFind( FullForm( GrfLabels, label, "Width", "astSet", class, status ), + nax, &id1, &id2, &id3, status ); + astSetWidth( this, id1, dval ); + if( nid > 1 ) astSetWidth( this, id2, dval ); + if( nid > 2 ) astSetWidth( this, id3, dval ); + +/* Size. */ +/* ----- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "size= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + for( id = 0; id < AST__NPID; id++ ) astSetSize( this, id, dval ); + +/* Size(label). */ +/* ------------ */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "size(%20[^()])= %lg %n", + label, &dval, &nc ) ) + && ( nc >= len ) ) { + class = astGetClass( this ); + + nid = IdFind( FullForm( GrfLabels, label, "Size", "astSet", class, status ), + nax, &id1, &id2, &id3, status ); + astSetSize( this, id1, dval ); + if( nid > 1 ) astSetSize( this, id2, dval ); + if( nid > 2 ) astSetSize( this, id3, dval ); + +/* TitleGap. */ +/* ----------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "titlegap= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + astSetTitleGap( this, dval ); + +/* MajTickLen. */ +/* ----------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "majticklen= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetMajTickLen( this, axis, dval ); + +/* MajTickLen(axis). */ +/* ----------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "majticklen(%d)= %lg %n", + &axis, &dval, &nc ) ) + && ( nc >= len ) ) { + astSetMajTickLen( this, axis - 1, dval ); + +/* MinTickLen. */ +/* ----------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "minticklen= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + for( axis = 0; axis < nax; axis++ ) astSetMinTickLen( this, axis, dval ); + +/* MinTickLen(axis). */ +/* ----------------- */ + } else if ( nc = 0, + ( 2 == astSscanf( setting, "minticklen(%d)= %lg %n", + &axis, &dval, &nc ) ) + && ( nc >= len ) ) { + astSetMinTickLen( this, axis - 1, dval ); + +/* Labelling. */ +/* -------- */ + } else if ( nc = 0, + ( 0 == astSscanf( setting, "labelling= %n%*s %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetLabelling( this, FullForm( "exterior interior", + setting + ival, setting, + "astSet", astGetClass( this ), status ) + ); + +/* If the attribute is still not recognised, pass it on to the parent + method for further interpretation. */ + } else { + (*parent_setattrib)( this_object, setting, status ); + } + +/* Undefine macros local to this function. */ +#undef MATCH +} + +static void SetLogPlot( AstPlot *this, int axis, int ival, int *status ){ +/* +* +* Name: +* SetLogPlot + +* Purpose: +* Set a new value for a LogPlot attribute + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void SetLogPlot( AstPlot *this, int axis, int ival, int *status ) + +* Class Membership: +* Plot member function + +* Description: +* Assigns a new value to the LogPlot attribute of the specified axis, +* and also re-maps the base Frame of the Plot if necessary. + +* Parameters: +* this +* The Plot. +* axis +* Zero based axis index. +* ival +* The new value for the ogPlot attribute. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + int oldval; /* Original attribute value */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Validate the axis index. */ + if( axis < 0 || axis >= 2 ){ + astError( AST__AXIIN, "astSetLogPlot(%s): Index (%d) is invalid for " + "attribute LogPlot - it should be in the range 1 to 2.", status, + astGetClass( this ), axis + 1 ); + +/* If the axis index is OK, store the original attribute value. We use + astGetLogPlot to get the value rather than directly accessing + "this->logplot" in order to get the any default value in the case of + no value having been set. */ + } else { + oldval = astGetLogPlot( this, axis ); + +/* If the current attribute value will change, attempt to re-map the plot + axis. If the attempt succeeds, toggle the current attribute value. */ + if( ( ival != 0 ) != ( oldval != 0 ) ){ + if( ToggleLogLin( this, axis, oldval, "astSetLogPlot", status ) ){ + this->logplot[ axis ] = ( !oldval ); + } + +/* If the current attribute value will not change, just store the supplied + value (this is not redundant because it may cause a previously defaulted + value to become an explicitly set value ). */ + } else { + this->logplot[ axis ] = oldval; + } + } +} + +static void SetTickValues( AstPlot *this, int axis, int nmajor, double *major, + int nminor, double *minor, int *status ){ +/* +*+ +* Name: +* astSetTickValues + +* Purpose: +* Store the tick mark values to use for a given Plot axis. + +* Type: +* Protected virtual function. + +* Synopsis: +* #include "plot.h" +* void astSetTickValues( AstPlot *this, int axis, int nmajor, +* double *major, int nminor, double *minor ) + +* Class Membership: +* Plot method. + +* Description: +* This function stores a set of tick mark values that should be used by +* subsequent calls to astGrid. + +* Parameters: +* this +* Pointer to a Plot. +* axis +* The zero-based index of the axis for which tick marks values +* have been supplied. +* nmajor +* The number of major tick mark values. If zero is supplied then +* the other parameters are ignored, and subsequent calls to +* astGrid will itself determine the tick values to be used. +* major +* Pointer to an array holding "nmajor" values for axis "axis" in +* the current Frame of the suppled Plot. Major tick marks will be +* drawn at these values. +* nminor +* The number of minor tick mark values. +* minor +* Pointer to an array holding "nminor" values for axis "axis" in +* the current Frame of the suppled Plot. Minor tick marks will be +* drawn at these values. + +*- +*/ + +/* Check the global status. */ + if( !astOK ) return; + +/* Report an error if the supplied axis value is incorrect. */ + if( axis < 0 || axis >= astGetNin( this ) ) { + astError( AST__INTER, "astSetTickValues(Plot): Supplied \"axis\" " + "value is %d - should in the range 0 to %d (internal AST " + "programming error).", status, axis, astGetNin( this ) - 1 ); + +/* Otherwise store or clear the values. */ + } else if( nmajor > 0 ){ + this->nmajtickval[ axis ] = nmajor; + this->majtickval[ axis ] = astStore( this->majtickval[ axis ], major, + sizeof( double )*nmajor ); + this->nmintickval[ axis ] = nminor; + this->mintickval[ axis ] = astStore( this->mintickval[ axis ], minor, + sizeof( double )*nminor ); + +/* Sort them into increasing order. */ + qsort( (void *) this->majtickval[ axis ], (size_t) nmajor, + sizeof(double), Compared ); + + qsort( (void *) this->mintickval[ axis ], (size_t) nminor, + sizeof(double), Compared ); + + } else { + this->nmajtickval[ axis ] = 0; + this->majtickval[ axis ] = astFree( this->majtickval[ axis ] ); + this->nmintickval[ axis ] = 0; + this->mintickval[ axis ] = astFree( this->mintickval[ axis ] ); + } +} + +const char *astStripEscapes_( const char *text, int *status ) { +/* +*++ +* Name: +c astStripEscapes +f AST_STRIPESCAPES + +* Purpose: +* Remove AST escape sequences from a string. + +* Type: +* Public function. + +* Synopsis: +c #include "plot.h" +c const char *astStripEscapes( const char *text ) +f RESULT = AST_STRIPESCAPES( TEXT ) + +* Description: +* This function removes AST escape sequences from a supplied string, +* returning the resulting text as the function value. The behaviour +* of this function can be controlled by invoking the +c astEscapes function, +f AST_ESCAPES routine, +* which can be used to supress or enable the removal of escape +* sequences by this function. +* +* AST escape sequences are used by the Plot class to modify the +* appearance and position of sub-strings within a plotted text string. +* See the "Escape" attribute for further information. + +* Parameters: +c text +c Pointer to the string to be checked. +f TEXT +f The string to be checked. + +* Returned Value: +c astStripEscapes() +f AST_STRIPESCAPES = CHARACTER +c Pointer to the modified string. If no escape sequences were found +c in the supplied string, then a copy of the supplied pointer is +c returned. Otherwise, the pointer will point to a static buffer +c holding the modified text. This text will be over-written by +c subsequent invocations of this function. If the astEscapes function +f The modified string. If the AST_ESCAPES routine +* has been called indicating that escape sequences should not be +* stripped, then the supplied string is returned without change. + +*-- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS + const char *a; + char *b; + int nc; + int ncc; + int type; + int value; + const char *result; + +/* Initialise */ + result= text; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Check inherited status and supplied pointer. Also return if the + string contains no escape sequences or if stripping of escapes has + been supressed. */ + if( !astOK || astEscapes( -1 ) || !text || !HasEscapes( text, status ) ) return result; + +/* Initialise a pointer to the next character to be read from the + supplied string. */ + a = text; + +/* Initialise a pointer to the next character to be written to the + returned string. */ + b = stripescapes_buff; + +/* Note the available space left in the buffer. */ + ncc = AST__PLOT_STRIPESCAPES_BUFF_LEN; + +/* Loop until all the string has been read, or the buffer is full. */ + while( *a && ncc > 0 ){ + +/* If the remaining string starts with an escape sequence, increment the + read point by the length of the escape sequence, but leave the write + pointer where it is. */ + if( astFindEscape( a, &type, &value, &nc ) ) { + a += nc; + +/* If the remaining string does not start with an escape sequence, copy + the following text from the read position to the write position. */ + } else { + if( nc > ncc ) nc = ncc; + memcpy( b, a, sizeof( char )*nc ); + a += nc; + b += nc; + ncc -= nc; + } + } + +/* Terminate the returned string. */ + *b = 0; + +/* Return the result.*/ + return stripescapes_buff; +} + +static int swapEdges( AstPlot *this, TickInfo **grid, AstPlotCurveData **cdata, int *status ) { +/* +* Name: +* swapEdges + +* Purpose: +* Determine if edges for text labels should be swapped. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int swapEdges( AstPlot *this, TickInfo **grid, AstPlotCurveData **cdata, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function returns a boolean result (0 or 1) to indicate whether +* or not it is necessary to swap the Edges(0) and Edges(1) attributes +* in order to place textual labels on appropriate edges. This should +* only be used if the attributes have not explicitly been set, and if +* interior labelling is being used. The sides are determines by +* looking at the bounding box of tick marks on axis 0, in graphics +* coordinates. The returned value causes the label for axis 0 to be +* placed on the edge parallel to the longest side of this bounding box. +* The label for axis 1 is placed parallel to the shortest side of this +* bounding box. + +* Parameters: +* this +* A pointer to the Plot. +* grid +* A pointer to an array of two TickInfo pointers (one for each axis), +* each pointing to a TickInfo structure holding information about +* tick marks on the axis. See function GridLines. +* cdata +* A pointer to an array of two AstPlotCurveData pointers (one for each axis), +* each pointing to an array of AstPlotCurveData structure (one for each +* major tick value on the axis), holding information about breaks +* in the curves drawn to mark the major tick values. See function +* DrawGrid. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* One if the edges should be swapped, otherwise zero. + +* Notes: +* - A value of zero will be returned if this function is invoked +* with the global status set, or if it should fail for any reason. +*/ + +/* Local Variables: */ + AstPlotCurveData *cdt; /* Pointer to the AstPlotCurveData for the next tick */ + TickInfo *info; /* Pointer to the TickInfo for the current axis */ + float xmax; /* Max graphics X value */ + float xmin; /* Min graphics X value */ + float ymax; /* Max graphics Y value */ + float ymin; /* Min graphics Y value */ + int oldedge; /* The original edge for axis 0 */ + int result; /* Swap edges? */ + int tick; /* Tick index */ + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Get a pointer to the structure containing information describing the + positions of the major tick marks along axis 0. */ + info = grid[ 0 ]; + +/* Get a pointer to the structure containing information describing + the breaks in the curve which is parallel to axis 1 and passes + through the first major tick mark on axis 0. */ + cdt = cdata[ 0 ]; + +/* Initialise the graphiocs X and Y bounds of the area covered by the + axis. */ + xmax = -1.0E10; + xmin = 1.0E10; + ymax = -1.0E10; + ymin = 1.0E10; + +/* Loop round each of the major tick marks on axis 0. */ + for( tick = 0; cdt && info && tick < info->nmajor; tick++ ){ + +/* Update the max and min graphics X and Y coords covered by the axis. */ + if( cdt->nbrk > 0 ) { + xmax = astMAX( xmax, cdt->xbrk[0] ); + xmin = astMIN( xmin, cdt->xbrk[0] ); + ymax = astMAX( ymax, cdt->ybrk[0] ); + ymin = astMIN( ymin, cdt->ybrk[0] ); + } + +/* Get a pointer to the curve through the next major tick mark. */ + cdt++; + + } + +/* See which edge axis 0 would normally be labelled on. */ + oldedge = astGetEdge( this, 0 ); + +/* If the X range is larger than the Y range, the textual label should be + placed on the bottom edge. If required, indicate that the edges must + be swapped to achieve this. */ + if( xmax - xmin > ymax - ymin ) { + if( oldedge == 0 || oldedge == 2 ) result = 1; + +/* If the X range is smaller than the Y range, the textual label should be + placed on the left edge. If required, indicate that the edges must + be swapped to achieve this. */ + } else { + if( oldedge == 1 || oldedge == 3 ) result = 1; + } + + return result; +} + +static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { +/* +* Name: +* TestAttrib + +* Purpose: +* Test if a specified attribute value is set for a Plot. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int TestAttrib( AstObject *this, const char *attrib, int *status ) + +* Class Membership: +* Plot member function (over-rides the astTestAttrib protected +* method inherited from the FrameSet class). + +* Description: +* This function returns a boolean result (0 or 1) to indicate whether +* a value has been set for one of a Plot's attributes. + +* Parameters: +* this +* Pointer to the Plot. +* attrib +* Pointer to a null terminated string specifying the attribute +* name. This should be in lower case with no surrounding white +* space. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* One if a value has been set, otherwise zero. + +* Notes: +* - A value of zero will be returned if this function is invoked +* with the global status set, or if it should fail for any reason. +*/ + +/* Local Variables: */ + AstPlot *this; /* Pointer to the Plot structure */ + char label[21]; /* Graphics item label */ + int axis; /* Axis number */ + int len; /* Length of attrib string */ + int nax; /* Number of base Frame axes */ + int nc; /* No. characters read by astSscanf */ + int result; /* Result value to return */ + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the Plot structure. */ + this = (AstPlot *) this_object; + +/* Get the number of base Frame axis (2 for a Plot, 3 for a Plot3D). */ + nax = astGetNin( this ); + +/* Obtain the length of the attrib string. */ + len = strlen( attrib ); + +/* Check the attribute name and test the appropriate attribute. */ + +/* Tol. */ +/* ---- */ + if ( !strcmp( attrib, "tol" ) ) { + result = astTestTol( this ); + +/* Edge(axis). */ +/* ----------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "edge(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestEdge( this, axis - 1 ); + +/* Grid. */ +/* ----- */ + } else if ( !strcmp( attrib, "grid" ) ) { + result = astTestGrid( this ); + +/* TickAll. */ +/* -------- */ + } else if ( !strcmp( attrib, "tickall" ) ) { + result = astTestTickAll( this ); + +/* ForceExterior */ +/* ------------- */ + } else if ( !strcmp( attrib, "forceexterior" ) ) { + result = astTestForceExterior( this ); + +/* Invisible. */ +/* ---------- */ + } else if ( !strcmp( attrib, "invisible" ) ) { + result = astTestInvisible( this ); + +/* Border. */ +/* ------- */ + } else if ( !strcmp( attrib, "border" ) ) { + result = astTestBorder( this ); + +/* ClipOp. */ +/* ------- */ + } else if ( !strcmp( attrib, "clipop" ) ) { + result = astTestClipOp( this ); + +/* Clip. */ +/* ----- */ + } else if ( !strcmp( attrib, "clip" ) ) { + result = astTestClip( this ); + +/* Grf. */ +/* ---- */ + } else if ( !strcmp( attrib, "grf" ) ) { + result = astTestGrf( this ); + +/* DrawTitle. */ +/* ---------- */ + } else if ( !strcmp( attrib, "drawtitle" ) ) { + result = astTestDrawTitle( this ); + +/* DrawAxes. */ +/* --------- */ + } else if ( !strcmp( attrib, "drawaxes" ) ) { + result = astTestDrawAxes( this, 0 ); + +/* DrawAxes(axis). */ +/* --------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "drawaxes(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestDrawAxes( this, axis - 1 ); + +/* Abbrev. */ +/* --------- */ + } else if ( !strcmp( attrib, "abbrev" ) ) { + result = astTestAbbrev( this, 0 ); + +/* Abbrev(axis). */ +/* --------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "abbrev(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestAbbrev( this, axis - 1 ); + +/* Escape. */ +/* ------- */ + } else if ( !strcmp( attrib, "escape" ) ) { + result = astTestEscape( this ); + +/* Gap. */ +/* ---- */ + } else if ( !strcmp( attrib, "gap" ) ) { + result = astTestGap( this, 0 ); + +/* Gap(axis). */ +/* ---------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "gap(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestGap( this, axis - 1 ); + +/* LabelAt(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "labelat(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestLabelAt( this, axis - 1 ); + +/* LogGap. */ +/* ---- */ + } else if ( !strcmp( attrib, "loggap" ) ) { + result = astTestLogGap( this, 0 ); + +/* LogGap(axis). */ +/* ---------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "loggap(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestLogGap( this, axis - 1 ); + +/* NumLabGap. */ +/* --------- */ + } else if ( !strcmp( attrib, "numlabgap" ) ) { + result = astTestNumLabGap( this, 0 ); + +/* NumLabGap(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "numlabgap(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestNumLabGap( this, axis - 1 ); + +/* TextLabGap. */ +/* --------- */ + } else if ( !strcmp( attrib, "textlabgap" ) ) { + result = astTestTextLabGap( this, 0 ); + +/* TextLabGap(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "textlabgap(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestTextLabGap( this, axis - 1 ); + +/* LabelUp. */ +/* -------- */ + } else if ( !strcmp( attrib, "labelup" ) ) { + result = astTestLabelUp( this, 0 ); + +/* LabelUp(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "labelup(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestLabelUp( this, axis - 1 ); + +/* LogPlot. */ +/* -------- */ + } else if ( !strcmp( attrib, "logplot" ) ) { + result = astTestLogPlot( this, 0 ); + +/* LogPlot(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "logplot(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestLogPlot( this, axis - 1 ); + +/* LogTicks. */ +/* -------- */ + } else if ( !strcmp( attrib, "logticks" ) ) { + result = astTestLogTicks( this, 0 ); + +/* LogTicks(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "logticks(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestLogTicks( this, axis - 1 ); + +/* LogLabel. */ +/* -------- */ + } else if ( !strcmp( attrib, "loglabel" ) ) { + result = astTestLogLabel( this, 0 ); + +/* LogLabel(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "loglabel(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestLogLabel( this, axis - 1 ); + +/* NumLab. */ +/* -------- */ + } else if ( !strcmp( attrib, "numlab" ) ) { + result = astTestNumLab( this, 0 ); + +/* NumLab(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "numlab(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestNumLab( this, axis - 1 ); + +/* MinTick. */ +/* -------- */ + } else if ( !strcmp( attrib, "mintick" ) ) { + result = astTestMinTick( this, 0 ); + +/* MinTick(axis). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "mintick(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestMinTick( this, axis - 1 ); + +/* TextLab. */ +/* ---------- */ + } else if ( !strcmp( attrib, "textlab" ) ) { + result = astTestTextLab( this, 0 ); + +/* TextLab(axis). */ +/* ---------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "textlab(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestTextLab( this, axis - 1 ); + +/* LabelUnits. */ +/* --------- */ + } else if ( !strcmp( attrib, "labelunits" ) ) { + result = astTestLabelUnits( this, 0 ); + +/* LabelUnits(axis). */ +/* --------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "labelunits(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestLabelUnits( this, axis - 1 ); + +/* Style. */ +/* ------ */ + } else if ( !strcmp( attrib, "style" ) ) { + result = TestUseStyle( this, AST__BORDER_ID, status ); + +/* Style(label). */ +/* ------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "style(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + result = TestUseStyle( this, FullForm( GrfLabels, label, attrib, "astTest", astGetClass( this ), status ), status ); + +/* Font. */ +/* ----- */ + } else if ( !strcmp( attrib, "font" ) ) { + result = TestUseFont( this, AST__TEXTLABS_ID, status ); + +/* Font(label). */ +/* ------------ */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "font(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + result = TestUseFont( this, FullForm( GrfLabels, label, attrib, "astTest", astGetClass( this ), status ), status ); + +/* Colour. */ +/* ------- */ + } else if ( !strcmp( attrib, "colour" ) ) { + result = TestUseColour( this, AST__TEXTLABS_ID, status ); + +/* Color. */ +/* ------- */ + } else if ( !strcmp( attrib, "color" ) ) { + result = TestUseColour( this, AST__TEXTLABS_ID, status ); + +/* Colour(label). */ +/* -------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "colour(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + result = TestUseColour( this, FullForm( GrfLabels, label, attrib, "astTest", astGetClass( this ), status ), status ); + +/* Color(label). */ +/* ------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "color(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + result = TestUseColour( this, FullForm( GrfLabels, label, attrib, "astTest", astGetClass( this ), status ), status ); + +/* Width. */ +/* ------ */ + } else if ( !strcmp( attrib, "width" ) ) { + result = TestUseWidth( this, AST__BORDER_ID, status ); + +/* Width(label). */ +/* ------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "width(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + result = TestUseWidth( this, FullForm( GrfLabels, label, attrib, "astTest", astGetClass( this ), status ), status ); + +/* Size. */ +/* ----- */ + } else if ( !strcmp( attrib, "size" ) ) { + result = TestUseSize( this, AST__TEXTLABS_ID, status ); + +/* Size(label). */ +/* ------------ */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "size(%20[^()])%n", label, &nc ) ) + && ( nc >= len ) ) { + result = TestUseSize( this, FullForm( GrfLabels, label, attrib, "astTest", astGetClass( this ), status ), status ); + +/* TitleGap. */ +/* --------- */ + } else if ( !strcmp( attrib, "titlegap" ) ) { + result = astTestTitleGap( this ); + +/* MajTickLen. */ +/* ----------- */ + } else if ( !strcmp( attrib, "majticklen" ) ) { + result = astTestMajTickLen( this, 0 ); + +/* MajTickLen(axis). */ +/* ---------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "majticklen(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestMajTickLen( this, axis - 1 ); + +/* MinTickLen. */ +/* ----------- */ + } else if ( !strcmp( attrib, "minticklen" ) ) { + result = astTestMinTickLen( this, 0 ); + +/* MinTickLen(axis). */ +/* ---------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( attrib, "minticklen(%d)%n", &axis, &nc ) ) + && ( nc >= len ) ) { + result = astTestMinTickLen( this, axis - 1 ); + +/* Labelling. */ +/* -------- */ + } else if ( !strcmp( attrib, "labelling" ) ) { + result = astTestLabelling( this ); + +/* If the attribute is still not recognised, pass it on to the parent + method for further interpretation. */ + } else { + result = (*parent_testattrib)( this_object, attrib, status ); + } + +/* Return the result, */ + return result; +} + +static void Text( AstPlot *this, const char *text, const double pos[], + const float up[], const char *just, int *status ){ +/* +*++ +* Name: +c astText +f AST_TEXT + +* Purpose: +* Draw a text string for a Plot. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "plot.h" +c void astText( AstPlot *this, const char *text, const double pos[], +c const float up[], const char *just ) +f CALL AST_TEXT( THIS, TEXT, POS, UP, JUST, STATUS ) + +* Class Membership: +* Plot method. + +* Description: +* This function draws a string of text at a position specified in +* the physical coordinate system of a Plot. The physical position +* is transformed into graphical coordinates to determine where the +* text should appear within the plotting area. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Plot. +c text +f TEXT = CHARACTER * ( * ) (Given) +c Pointer to a null-terminated character string containing the +f A character string containing the +* text to be drawn. Trailing white space is ignored. +c pos +f POS( * ) = DOUBLE PRECISION (Given) +* An array, with one element for each axis of the Plot, giving +* the physical coordinates of the point where the reference +* position of the text string is to be placed. +c up +f UP( * ) = REAL (Given) +* An array holding the components of a vector in the "up" +* direction of the text (in graphical coordinates). For +c example, to get horizontal text, the vector {0.0f,1.0f} should +f example, to get horizontal text, the vector [0.0,1.0] should +* be supplied. For a basic Plot, 2 values should be supplied. For +* a Plot3D, 3 values should be supplied, and the actual up vector +* used is the projection of the supplied up vector onto the text plane +* specified by the current value of the Plot3D's Norm attribute. +c just +f JUST = CHARACTER * ( * ) (Given) +c Pointer to a null-terminated character string identifying the +f A character string identifying the +* reference point for the text being drawn. The first character in +* this string identifies the reference position in the "up" direction +* and may be "B" (baseline), "C" (centre), "T" (top) or "M" (bottom). +* The second character identifies the side-to-side reference position +* and may be "L" (left), "C" (centre) or "R" (right ). The string is +* case-insensitive, and only the first two characters are significant. +* +* For example, a value of "BL" means that the left end of the +* baseline of the original (un-rotated) text is to be drawn at the +c position given by "pos". +f position given by POS. + +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +* - The Plot3D class currently does not interpret graphical escape +* sequences contained within text displayed using this method. +* - Text is not drawn at positions which have any coordinate equal +* to the value AST__BAD (or where the transformation into +* graphical coordinates yields coordinates containing the value +* AST__BAD). +c - If the plotting position is clipped (see astClip), then no +f - If the plotting position is clipped (see AST_CLIP), then no +* text is drawn. +* - An error results if the base Frame of the Plot is not +* 2-dimensional or (for a Plot3D) 3-dimensional. +* - An error also results if the transformation between the +* current and base Frames of the Plot is not defined (i.e. the +* Plot's TranInverse attribute is zero). +*-- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstMapping *mapping; /* Pointer to graphics->physical mapping */ + AstPointSet *pset1; /* PointSet holding physical positions */ + AstPointSet *pset2; /* PointSet holding graphics positions */ + const char *class; /* Object class */ + const char *method; /* Current method */ + const double **ptr1; /* Pointer to physical positions */ + char ljust[3]; /* Upper case copy of "just" */ + char *ltext; /* Local copy of "text" excluding trailing spaces */ + double **ptr2; /* Pointer to graphics positions */ + float xbn[ 4 ]; /* X coords of text bounding box. */ + float ybn[ 4 ]; /* Y coord of text bounding box. */ + int axis; /* Axis index */ + int escs; /* Original astEscapes value */ + int naxes; /* No. of axes in the base Frame */ + int ncoord; /* No. of axes in the current Frame */ + int ulen; /* Length of "text" excluding trailing spaces */ + +/* Check the global error status. */ + if ( !astOK || !text ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Store the current method and class for inclusion in error messages + generated by lower level functions. */ + method = "astText"; + class = astClass( this ); + +/* Check the base Frame of the Plot is 2-D. */ + naxes = astGetNin( this ); + if( naxes != 2 && astOK ){ + astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " + "Frame of the supplied %s is invalid - this number should " + "be 2.", status, method, class, naxes, class ); + } + +/* Ensure AST functions included graphical escape sequences in any + returned text strings. */ + escs = astEscapes( 1 ); + +/* Initialise the bounding box for primatives produced by this call. */ + if( !Boxp_freeze ) { + Boxp_lbnd[ 0 ] = FLT_MAX; + Boxp_lbnd[ 1 ] = FLT_MAX; + Boxp_ubnd[ 0 ] = FLT_MIN; + Boxp_ubnd[ 1 ] = FLT_MIN; + } + +/* Indicate that the GRF module should re-calculate it's cached values + (in case the state of the graphics system has changed since the last + thing was drawn). */ + RESET_GRF; + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + astGrfAttrs( this, AST__TEXT_ID, 1, GRF__TEXT, method, class ); + +/* Get the number of coordinates in the physical coordinate frame. */ + ncoord = astGetNout( this ); + +/* Create a PointSet to hold the supplied physical coordinates. */ + pset1 = astPointSet( 1, ncoord, "", status ); + +/* Allocate memory to hold pointers to the first value on each axis. */ + ptr1 = (const double **) astMalloc( sizeof( const double * )* + (size_t)( ncoord )); + +/* Check the pointer can be used, then store pointers to the first value + on each axis. */ + if( astOK ){ + for( axis = 0; axis < ncoord; axis++ ){ + ptr1[ axis ] = pos + axis; + } + } + +/* Store these pointers in the PointSet. */ + astSetPoints( pset1, (double **) ptr1 ); + +/* Transform the supplied data from the current frame (i.e. physical + coordinates) to the base frame (i.e. graphics coordinates) using + the inverse Mapping defined by the Plot. */ + mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); + pset2 = Trans( this, NULL, mapping, pset1, 0, NULL, 0, method, class, status ); + mapping = astAnnul( mapping ); + +/* Get pointers to the graphics coordinates. */ + ptr2 = astGetPoints( pset2 ); + +/* Take a copy of the string excluding any trailing white space. */ + ulen = ChrLen( text, status ); + ltext = (char *) astStore( NULL, (void *) text, ulen + 1 ); + +/* Check the pointers can be used. */ + if( astOK ){ + +/* Terminate the local copy of the text string. */ + ltext[ ulen ] = 0; + +/* Produce an upper-case copy of the first two characters in "just". */ + ljust[0] = (char) toupper( (int) just[0] ); + ljust[1] = (char) toupper( (int) just[1] ); + ljust[2] = 0; + +/* Convert the double precision values to single precision, checking for + bad positions. */ + if( ptr2[0][0] != AST__BAD && ptr2[1][0] != AST__BAD ){ + +/* Draw the text string. */ + DrawText( this, 1, astGetEscape( this ), ltext, (float) ptr2[0][0], + (float) ptr2[1][0], ljust, up[ 0 ], up[ 1 ], xbn, ybn, + NULL, method, class, status ); + } + +/* Free the local copy of the string. */ + ltext = (char *) astFree( (void *) ltext ); + + } + +/* Annul the PointSets. */ + pset1 = astAnnul( pset1 ); + pset2 = astAnnul( pset2 ); + +/* Free the memory holding the pointers to the first value on each axis. */ + ptr1 = (const double **) astFree( (void *) ptr1 ); + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, AST__TEXT_ID, 0, GRF__TEXT, method, class ); + +/* Restore the original value of the flag which says whether graphical + escape sequences should be incldued in any returned text strings. */ + astEscapes( escs ); + +/* Return */ + return; +} + +static void TextLabels( AstPlot *this, int edgeticks, int dounits[2], + const char *method, const char *class, int *status ){ +/* +* +* Name: +* TextLabels + +* Purpose: +* Draw textual labels round a grid. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void TextLabels( AstPlot *this, int edgeticks, int dounits[2], +* const char *method, const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function displays a textual label for each physical axis, and a +* title. The text strings are obtained from the Label and Title +* attributes of the current Frame in the Plot. + +* Parameters: +* this +* A pointer to the Plot. +* edgeticks +* If tick marks and numerical labels were drawn around the edges +* of the plotting area, this should be supplied as 1. Otherwise it +* should be supplied as zero. +* dounits +* Flags indicating if the axis Units string should be included in +* the edge labels. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + char *new_text; /* Pointer to complete text string (inc. units) */ + char *just; /* Pointer to axis label justification string */ + const char *text; /* Pointer to text string to be displayed */ + const char *units; /* Pointer to text string describing the units */ + double mindim; /* Minimum dimension of plotting area */ + double xrange; /* Width of plotting area */ + double yrange; /* Height of plotting area */ + float txtgap; /* Gap between bounding box and text string */ + float upx; /* X component of text up-vector */ + float upy; /* Y component of text up-vector */ + float xbn[ 4 ]; /* X coords at corners of new label's bounding box */ + float ybn[ 4 ]; /* Y coords at corners of new label's bounding box */ + float xref; /* Graphics X coord. at text ref. position */ + float yref; /* Graphics Y coord. at text ref. position */ + float xlo, xhi, ylo, yhi;/* The original bounding box (excluding labels) */ + int axis; /* Axis index */ + int draw; /* Should label be drawn? */ + int edge; /* Edge to be labelled */ + int esc; /* Interpret escape sequences? */ + int gelid; /* ID for next graphical element to be drawn */ + int tlen; /* No. of characetsr in label */ + int ulen; /* No. of characetsr in units */ + +/* Check the global status. */ + if( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(this); + +/* Get the minimum dimension of the plotting area. */ + xrange = this->xhi - this->xlo; + yrange = this->yhi - this->ylo; + mindim = astMIN( xrange, yrange ); + +/* Take a copy of the bounding box which encloses all other parts of the + annotated grid. If nothing has been plotted, use an area 20 % smaller + than the plotting area. */ + if( Box_lbnd[ 0 ] != FLT_MAX ) { + xlo = Box_lbnd[ 0 ]; + xhi = Box_ubnd[ 0 ]; + ylo = Box_lbnd[ 1 ]; + yhi = Box_ubnd[ 1 ]; + } else { + xlo = this->xlo + 0.2*xrange; + xhi = this->xhi - 0.2*xrange; + ylo = this->ylo + 0.2*yrange; + yhi = this->yhi - 0.2*yrange; + } + +/* See if escape sequences are to be interpreted within the labels. */ + esc = astGetEscape( this ); + +/* Initialize the id value for graphical element being drawn. */ + gelid = AST__TEXTLAB1_ID; + +/* Now write a label for each physical axis. */ + for( axis = 0; axis < 2 && astOK; axis++ ){ + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + astGrfAttrs( this, gelid, 1, GRF__TEXT, method, class ); + +/* See if the label is to be drawn. If an explicit value has not been set + for the TextLab attribute, the default is to draw the label if tick + marks were draw round the edge of the plotting area, and not to + otherwise. */ + if( astTestTextLab( this, axis ) ){ + draw = astGetTextLab( this, axis ); + } else { + draw = edgeticks; + } + +/* If so get the label. */ + if( draw ){ + text = astGetLabel( this, axis ); + tlen = ChrLen( text, status ); + +/* If required, get the units string and concatenate it with the label (inside + parenthesise). Ignore trailing spaces. */ + if( dounits[ axis ] ){ + units = astGetUnit( this, axis ); + if( units && units[0] ){ + ulen = ChrLen( units, status ); + new_text = astMalloc( tlen + ulen + 4 ); + if( new_text ) memcpy( new_text, text, tlen ); + + text = new_text + tlen; + + memcpy( (void *) text, " (", 2 ); + text += 2; + + memcpy( (char *) text, units, ulen ); + text += ulen; + + memcpy( (char *) text, ")", 1 ); + text += 1; + + ( (char *) text )[0] = 0; + + text = new_text; + + } else { + new_text = astStore( NULL, (void *) text, tlen + 1 ); + new_text[ tlen ] = 0; + text = new_text; + units = NULL; + } + + } else { + new_text = astStore( NULL, (void *) text, tlen + 1 ); + new_text[ tlen ] = 0; + text = new_text; + units = NULL; + } + +/* Get the gap between the edge of the bounding box and the closest edge + of the text string. */ + txtgap = (float)( mindim*astGetTextLabGap( this, axis ) ); + +/* Get the edge to be labelled. Edge 0 is the left hand edge. Edge 1 is the + top edge. Edge 2 is the right-hand edge. Edge 3 is the bottom edge. */ + edge = astGetEdge( this, axis ) % 4; + if( edge < 0 ) edge = -edge; + +/* If the label is to be put on the left hand edge... */ + if( edge == 0 ){ + +/* Set the up vector so that the text is written from bottom to top. */ + upx = -1.0; + upy = 0.0; + +/* Justify the bottom of the whole bounding box (not just the text + base-line). */ + just = "MC"; + +/* Set the x reference position just outside the box enclosing all the + graphics drawn so far. The reference point refers to the centre of the + text string in both directions ("CC" justification). Take account of + whether or not the x axis is reversed. Do not allow the text to be + written outside the whole plotting surface. */ + if( this->xrev ){ + xref = xhi + txtgap; + } else { + xref = xlo - txtgap; + } + +/* The Y reference position is at the mid point vertically. */ + yref = 0.5*( astMIN( yhi, this->yhi ) + + astMAX( ylo, this->ylo ) ); + +/* Do the same for the top edge. */ + } else if( edge == 1 ){ + upx = 0.0; + upy = 1.0; + just = "MC"; + if( this->yrev ){ + yref = ylo - txtgap; + } else { + yref = yhi + txtgap; + } + xref = 0.5*( astMIN( xhi, this->xhi ) + + astMAX( xlo, this->xlo ) ); + +/* Do the same for the right-hand edge. */ + } else if( edge == 2 ){ + upx = 1.0; + upy = 0.0; + just = "MC"; + if( this->xrev ){ + xref = xlo - txtgap; + } else { + xref = xhi + txtgap; + } + yref = 0.5*( astMIN( yhi, this->yhi ) + + astMAX( ylo, this->ylo ) ); + +/* Do the same for the bottom edge. */ + } else { + upx = 0.0; + upy = 1.0; + just = "TC"; + if( this->yrev ){ + yref = yhi + txtgap; + } else { + yref = ylo - txtgap; + } + xref = 0.5*( astMIN( xhi, this->xhi ) + + astMAX( xlo, this->xlo ) ); + } + +/* Display the label. */ + DrawText( this, 1, esc, text, xref, yref, just, + upx, upy, xbn, ybn, NULL, method, class, status ); + +/* Release the memory allocated to store the axis label;. */ + new_text = (char *) astFree( (void *) new_text ); + text = NULL; + + } + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, gelid, 0, GRF__TEXT, method, class ); + +/* Set up the id for the next graphical element to be drawn. */ + gelid = AST__TEXTLAB2_ID; + + } + +/* See if the title is to be drawn. */ + if( astOK && astGetDrawTitle( this ) ){ + +/* If so get the title. */ + text = astGetTitle( this ); + +/* Create a copy from which trailing spaces have been removed. */ + tlen = ChrLen( text, status ); + new_text = (char *) astStore( NULL, (void *) text, tlen + 1 ); + new_text[ tlen ] = 0; + text = new_text; + +/* Establish the correct graphical attributes as defined by attributes + with the supplied Plot. */ + astGrfAttrs( this, AST__TITLE_ID, 1, GRF__TEXT, method, class ); + +/* Take a copy of the bounding box which encloses all other parts of the + annotated grid (this may have been extended by the above code). If + nothing has been plotted, use an area 20 % smaller than the plotting + area. */ + if( Box_lbnd[ 0 ] != FLT_MAX ) { + xlo = Box_lbnd[ 0 ]; + xhi = Box_ubnd[ 0 ]; + ylo = Box_lbnd[ 1 ]; + yhi = Box_ubnd[ 1 ]; + } else { + xlo = this->xlo + 0.2*xrange; + xhi = this->xhi - 0.2*xrange; + ylo = this->ylo + 0.2*yrange; + yhi = this->yhi - 0.2*yrange; + } + +/* Get the graphics coordinates of the bottom centre point of the title. + The X centre is put at the mid point of the used x axis range + (restricted to the range of the plotting area). */ + xref = 0.5*( astMIN( xhi, this->xhi ) + + astMAX( xlo, this->xlo ) ); + +/* The Y centre is put a "TitleGap" distance outside the box containing + the everything else. */ + if( this->yrev ){ + yref = ylo - (float)( mindim*astGetTitleGap( this ) ); + } else { + yref = yhi + (float)( mindim*astGetTitleGap( this ) ); + } + +/* Display the title. Justify the bottom of the whole bounding box (not + just the text base-line). */ + DrawText( this, 1, esc, text, xref, yref, "MC", 0.0F, 1.0F, + xbn, ybn, NULL, method, class, status ); + +/* Re-establish the original graphical attributes. */ + astGrfAttrs( this, AST__TITLE_ID, 0, GRF__TEXT, method, class ); + +/* Release the memory allocated to store the title. */ + new_text = (char *) astFree( (void *) new_text ); + text = NULL; + } + +/* Include the labels in the bounding box held in global variables + Box_lbnd/ubnd. */ + if( Box_lbnd[ 0 ] != FLT_MAX ) { + Box_lbnd[ 0 ] = astMIN( Box_lbnd[ 0 ], Boxp_lbnd[ 0 ] ); + Box_ubnd[ 0 ] = astMAX( Box_ubnd[ 0 ], Boxp_ubnd[ 0 ] ); + Box_lbnd[ 1 ] = astMIN( Box_lbnd[ 1 ], Boxp_lbnd[ 1 ] ); + Box_ubnd[ 1 ] = astMAX( Box_ubnd[ 1 ], Boxp_ubnd[ 1 ] ); + } else { + Box_lbnd[ 0 ] = Boxp_lbnd[ 0 ]; + Box_ubnd[ 0 ] = Boxp_ubnd[ 0 ]; + Box_lbnd[ 1 ] = Boxp_lbnd[ 1 ]; + Box_ubnd[ 1 ] = Boxp_ubnd[ 1 ]; + } + +/* Return. */ + return; + +} + +static void UpdateConcat( float *xbn, float *ybn, float ux, float uy, + float rx, float ry, float *x, float *y, + float x0, float y0, float *alpha_lo, + float *alpha_hi, float *beta_lo, float *beta_hi, + int *status ){ + +/* +* Name: +* UpdateConcat + +* Purpose: +* Update the concatenation point for a text string in preparation for +* appending another string. + +* Synopsis: +* #include "plot.h" +* void UpdateConcat( float *xbn, float *ybn, float ux, float uy, +* float rx, float ry, float *x, float *y, +* float x0, float y0, float *alpha_lo, float *alpha_hi, +* float *beta_lo, float *beta_hi, int *status ) + +* Description: +* This function modifies the supplied concatenation point (x,y) by moving +* it to the right along the baseline of the text by an amount equal +* to the width of the supplied sub-string bounding box. It also updates +* the supplied total bounding box so that it includes the supplied +* sub-string bounding box. + +* Parameters: +* xbn +* Pointer to an array holding the x coord at the four corners of +* the sub-string bounding box. +* ybn +* Pointer to an array holding the y coord at the four corners of +* the sub-string bounding box. +* ux +* The x component of the up-vector for the text, in graphics coords. +* The length of this vector should be equal to the height of normal +* text drawn with this up-vector. +* uy +* The y component of the up-vector for the text. See "ux". +* rx +* The x component of the right-vector for the text. The length of this +* vector should be equal to the height of normal text drawn with the +* supplied up-vector. +* ry +* The y component of the right-vector for the text. see "rx". +* x +* Pointer to a float holding the x coord of the concatenation point +* of the text just drawn. This is changed on exit so that the next +* string will be appended to the end of the text just drawn. +* y +* Pointer to a float holding the y coord of the concatenation point +* of the text just drawn. This is changed on exit so that the next +* string will be appended to the end of the text just drawn. +* x0 +* The X coord at the left end of the baseline of the total string. +* y0 +* The Y coord at the left end of the baseline of the total string. +* alpha_lo +* Pointer to a double holding a value which gives the position of the +* bottom edge of the total bounding box. The value is such that +* (x0,y0) + alpha_lo*(ux,uy) is a point on the bottom edge of the +* total bounding box. The returned value is updated so that the +* total bounding box includes the supplied sub-string bounding box. +* alpha_hi +* Pointer to a double holding a value which gives the position of the +* top edge of the total bounding box. The value is such that +* (x0,y0) + alpha_hi*(ux,uy) is a point on the top edge of the +* total bounding box. The returned value is updated so that the +* total bounding box includes the supplied sub-string bounding box. +* beta_lo +* Pointer to a double holding a value which gives the position of the +* left edge of the total bounding box. The value is such that +* (x0,y0) + beta_lo*(rx,ry) is a point on the left edge of the +* total bounding box. The returned value is updated so that the +* total bounding box includes the supplied sub-string bounding box. +* beta_hi +* Pointer to a double holding a value which gives the position of the +* right edge of the total bounding box. The value is such that +* (x0,y0) + beta_hi*(rx,ry) is a point on the right edge of the +* total bounding box. The returned value is updated so that the +* total bounding box includes the supplied sub-string bounding box. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + float ahi; + float alo; + float alpha; + float beta; + float bhi; + float blo; + float denom; + float dx; + float dy; + float xc; + float yc; + int ic; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Check the supplied up and right vectors are not parallel. */ + denom = ux*ry - uy*rx; + if( denom != 0.0 ) { + +/* Get the coords at the centre of the sub-string bounding box. */ + xc = ( xbn[ 0 ] + xbn[ 1 ] + xbn[ 2 ] + xbn[ 3 ] )/4.0; + yc = ( ybn[ 0 ] + ybn[ 1 ] + ybn[ 2 ] + ybn[ 3 ] )/4.0; + +/* For each of the 4 corners of the sub-string bounding box, we consider the + vector from the centre of the bounding box to the corner. We want to express + this vector, vx, as a sum of a vector in the up direction and a vector + in the right direction: + + vx = alpha*ux + beta+rx + vy = alpha*uy + beta+ry + + where alpha and beta are constants which are different for each + corner vector. We also want to find the minimum and maximum alpha and + beta covered by the box. First initialise the limits. */ + alo = 0.0; + ahi = 0.0; + blo = 0.0; + bhi = 0.0; + +/* Now find alpha and beta for each of the four corners. */ + for( ic = 0; ic < 4; ic++ ) { + dx = xbn[ ic ] - xc; + dy = ybn[ ic ] - yc; + alpha = ( dx*ry - dy*rx ) /denom; + beta = ( dy*ux - dx*uy ) /denom; + +/* Extend the bounds in alpha and beta. */ + if( alpha < alo ) alo = alpha; + if( alpha > ahi ) ahi = alpha; + if( beta < blo ) blo = beta; + if( beta > bhi ) bhi = beta; + +/* The bottom left corner has negative values for both alpha and beta. + Commence the process of updating the concatenation point by subtracting + off the coordinates at the bottom left corner. For zero height bounding + boxes (such as may be produced if the text is completely blank), the + "alpha" value should be zero, but may be slightly non-zero due to + rounding errors. Allow for this (assuming non-blank text will always + produce a boundiong box that is at least 1.0E-4 of the up vector in + height). We do the same for bounding box width (although zero width + boxes will probably not occur). */ + if( alpha < 1.0E-4 ) { + if( beta < 1.0E-4 ) { + *x -= xbn[ ic ]; + *y -= ybn[ ic ]; + +/* The bottom right corner has negative alpha and positive beta. Complete + the process of updating the concatenation point by adding on the + coordinates at the bottom right corner. */ + } else if( beta > -1.0E-4 ) { + *x += xbn[ ic ]; + *y += ybn[ ic ]; + } + } + } + +/* Also express the vector from (x0,y0) to (xc,yc) as a sum of a vector + in the up direction and a vector in the right direction: + + xc - x0 = alpha*ux + beta*rx + yc - y0 = alpha*uy + beta*ry + + Find alpha and beta. */ + + dx = xc - x0; + dy = yc - y0; + alpha = ( dx*ry - dy*rx ) /denom; + beta = ( dy*ux - dx*uy ) /denom; + +/* We can now express the vector from (x0,y0) to each of the 4 corners as + a sum of alpha*up and beta*right. Form the bounds of the sub-string in + terms of up-vectors and right vectors from (x0,y0) instead of from the + centre of the box. */ + alo += alpha; + ahi += alpha; + blo += beta; + bhi += beta; + +/* Extend the supplied alpha and beta bounding box to include these limits. */ + if( alo < *alpha_lo ) *alpha_lo = alo; + if( ahi > *alpha_hi ) *alpha_hi = ahi; + if( blo < *beta_lo ) *beta_lo = blo; + if( bhi > *beta_hi ) *beta_hi = bhi; + } +} + +static void Ticker( AstPlot *this, int edge, int axis, double value, + double *gap, double tklen, int majtick, int save, + EdgeCrossingsStatics **pstatics, const char *method, + const char *class, int *status ){ +/* +* +* Name: +* Ticker + +* Purpose: +* Draw edge tick marks for a given axis value. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* void Ticker( AstPlot *this, int edge, int axis, double value, +* double *gap, double tklen, int majtick, int save, +* EdgeCrossingsStatics **pstatics, const char *method, +* const char *class, int *status ){ + +* Class Membership: +* Plot member function. + +* Description: +* This function draws tick marks at all occurences of a given +* physical axis value on a given edge of the plotting area. + +* Parameters: +* this +* A pointer to the Plot. +* edge +* The edge of the plotting area to be ticked. Edge 0 is the left hand +* edge. Edge 1 is the top edge. Edge 2 is the right-hand edge. Edge 3 +* is the bottom edge. +* axis +* The index of the axis to which "value" refers. The tick mark extends +* parallel to this axis. +* value +* The physical axis value at which to place the tick mark. +* gap +* Pointer to array of two values holding the gap between major +* tick marks on the two axes. +* tklen +* The length of the tick, in graphics units. +* majtick +* Non-zero if the tick mark being drawn is a major tick, and zero +* if it is a minor tick. +* save +* If non-zero, the tick mark position will be saved in the Plot structure. +* pstatics +* Address of a pointer to a structure holding values for variables +* which were statically defined within this function prior to the +* thread-safe version of AST. If the pointer is supplied as NULL, +* then a new structure is allocated and initialised. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + double *cross; /* Pointer to crossings information */ + double *vx; /* Pointer to next X vector component value */ + double *vy; /* Pointer to next Y vector component value */ + double *x; /* Pointer to next X value */ + double *y; /* Pointer to next Y value */ + double xe; /* X at tick end */ + double ye; /* Y at tick end */ + int j; /* Crossing index */ + int ncross; /* No. of crossings of tick value and edge */ + +/* Check the global status. */ + if( !astOK ) return; + +/* See where the current major tick value crosses the edge. */ + ncross = EdgeCrossings( this, edge, axis, value, gap, &cross, pstatics, + method, class, status ); + +/* Do nothing if the supplied axis value does not occur on the specified + edge of the plotting area. */ + if( ncross ){ + +/* Draw major tick marks at the crossings. */ + x = cross; + y = cross + 1; + vx = cross + 2; + vy = cross + 3; + +/* Draw a tick mark at each occurence of the axis value on the specified + edge. */ + for( j = 0; j < ncross; j++ ){ + +/* Check the tick mark position and directionm are defined. */ + if( *vx != AST__BAD && *vy != AST__BAD && + *x != AST__BAD && *y != AST__BAD ){ + +/* Ensure the tick mark will point into the plotting area, no matter which + edge it is on. First ensure the direction vector refers to a system in + which X increases to the left and Y increases upwards. */ + if( this->xrev ) *vx = -*vx; + if( this->yrev ) *vy = -*vy; + +/* If necessary reverse the vector so that it points into the plotting + area. How to do this depends on which edge is being ticked. */ + if( ( edge == 0 && *vx < 0.0 ) || /* left-hand edge */ + ( edge == 1 && *vy > 0.0 ) || /* Top edge */ + ( edge == 2 && *vx > 0.0 ) || /* Right-hand edge */ + ( edge == 3 && *vy < 0.0 ) ){ /* Bottom edge */ + + *vx = -*vx; + *vy = -*vy; + } + +/* Now ensure the direction vector refers to a the native graphics system + taking account of any reversal of axes. */ + if( this->xrev ) *vx = -*vx; + if( this->yrev ) *vy = -*vy; + +/* Do not draw the tick if the start of the tick is outside the bounds of + the axis it is labelling. */ + if( ( ( edge == 1 || edge == 3 ) && + *x < this->xhi && *x > this->xlo ) || + ( ( edge == 0 || edge == 2 ) && + *y < this->yhi && *y > this->ylo ) ) { + +/* Store the x and y graphics coords of the far end of the tick mark */ + xe = *x + tklen*(*vx); + ye = *y + tklen*(*vy); + +/* Ensure the far end of the tick mark is within the bounds of the axis + it is labelling. If not, redice the length of the tick mark until it is.*/ + if( edge == 1 || edge == 3 ) { /* Top or bottom edge */ + if( xe > this->xhi ) { + ye = *y + tklen*(*vy)*( this->xhi - *x )/(xe - *x ); + xe = this->xhi; + } else if( xe < this->xlo ) { + ye = *y + tklen*(*vy)*( this->xlo - *x )/(xe - *x ); + xe = this->xlo; + } + + } else { /* Left or right edge */ + if( ye > this->yhi ) { + xe = *x + tklen*(*vx)*( this->yhi - *y )/(ye - *y ); + ye = this->yhi; + } else if( ye < this->ylo ) { + xe = *x + tklen*(*vx)*( this->ylo - *y )/(ye - *y ); + ye = this->ylo; + } + } + +/* Draw the tick mark as a straight line of the specified length. */ + if( save ) SaveTick( this, axis, *x, *y, majtick, status ); + if( *x != xe || *y != ye ) { + Bpoly( this, (float) *x, (float) *y, status ); + Apoly( this, (float) xe, (float) ye, status ); + Opoly( this, status ); + } + } + +/* Move on to the next crossing. */ + x += 4; + y += 4; + vx += 4; + vy += 4; + } + } + +/* Free the memory holding the crossings. */ + if( cross ) cross = (double *) astFree( (void *) cross ); + + } + +/* Return. */ + return; + +} + +static TickInfo *TickMarks( AstPlot *this, int axis, double *cen, double *gap, + int *inval, GetTicksStatics **pstatics, + const char *method, const char *class, int *status ){ +/* +* Name: +* TickMarks + +* Purpose: +* Obtain a list of tick mark values and labels for a single axis in a 2-D +* physical coordinate Frame. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* TickInfo *TickMarks( AstPlot *this, int axis, double *cen, double *gap, +* int *inval, GetTicksStatics **pstatics, +* const char *method, const char *class, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* A set of tick marks values and corresponding formatted labels are +* found for an axis which result in all adjacent labels being different, +* but using the minimum number of digits of precision in the formatting. +* This algorithm is over-ridden if the caller has set an explicit Format +* string for the axis. The gap between tick marks can be specified by +* the caller or a default value may be found automatically. + +* Parameters: +* this +* The Plot. +* axis +* The zero-based index of the axis to use. +* cen +* Pointer to the supplied axis value at which to put a single +* central tick. Other ticks will be placed evenly on either side of +* this tick. If AST__BAD is provided, a value will be used which +* would put a tick at an axis value of zero. The used value is +* returned. +* gap +* The supplied values for the gaps between ticks on the axis. If +* this is AST__BAD a suitable default value will be used and +* returned in place of the AST__BAD value. +* inval +* A pointer to a location at which to return a flag indicating if +* any invalid physical coordinates were encountered while deciding on +* the tick values. +* pstatics +* Address of a pointer to a structure holding static data values +* used within the GetTicks function. A NULL pointer should be supplied +* on the first invocation (dynamic memory will then be allocated to +* hold ths structure). The memory is freed when a NULL value for +* "this" is supplied. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to a TickInfo structure holding information about the tick +* marks (no. of major and minor ticks, the major tick mark values and +* labels). This structure should be freed, together with its contents, +* using astFree when it is no longer needed. + +* Notes: +* - The returned labels are NOT abbreviated to remove identical +* leading fields. +* - This function allocates some static resources on its first +* invocation, which should be released when no longer needed, or when +* a different Plot is supplied, by calling this function with a NULL +* pointer for parameter "this". All other parameters (except axis) are +* ignored. +* - This function assumes that the physical coordinate system is 2 +* dimensional, and it should not be used if this is not the case. +* - An error is reported if the region containing valid physical +* coordinates is too small to use. +* - If an error has already occurred, or if this function should fail +* for any reason, then a NULL pointer is returned. +*/ + +/* Local Constants: */ +#define MAXFLD 10 + +/* Local Variables: */ + AstAxis *ax; /* Pointer to the axis. */ + AstFrame *frame; /* Pointer to the current Frame in the Plot */ + TickInfo *ret; /* Pointer to the returned structure. */ + char **labels; /* Pointer to list of formatted labels */ + char **newlabels; /* Pointer to new list of shortened formatted labels */ + char **oldlabels; /* Pointer to old list of formatted labels */ + char *fields[ MAXFLD ]; /* Pointers to starts of fields in a label */ + char *old_format; /* Original Format string */ + char *used_fmt; /* Copy of format string actually used */ + const char *a; /* Pointer to next character to consider */ + const char *fmt; /* Format string actually used */ + double *ticks; /* Pointer to major tick mark values */ + double *minticks; /* Pointer to minor tick mark values */ + double cen0; /* Supplied value of cen */ + double junk; /* Unused value */ + double refval; /* Value for other axis to use when normalizing */ + double used_gap; /* The gap size actually used */ + int bot_digits; /* Digits value which makes labels as short as possible */ + int digits; /* New Digits value */ + int digset; /* Did the format string fix the no. of digits to use? */ + int fmtset; /* Was a format set? */ + int i; /* Tick index. */ + int nc[ MAXFLD ]; /* Lengths of fields in a label */ + int nf; /* Number of fields in a label */ + int nmajor; /* No. of major tick marks */ + int nminor; /* No. of minor tick marks */ + int ok; /* Are all adjacent labels different? */ + int reset_fmt; /* Re-instate the original state of the Format attribute? */ + + +/* If a NULL pointer has been supplied for "this", release the resources + allocated within GetTicks, and return. */ + if( !this ){ + (void) GetTicks( NULL, axis, NULL, &ticks, &nmajor, &minticks, &nminor, + 0, inval, &refval, pstatics, method, class, status ); + return NULL; + } + +/* Check the global status. */ + if( !astOK ) return NULL; + +/* Initialise the returned pointer. */ + ret = NULL; + +/* Store the supplied value of cen. */ + cen0 = cen ? *cen : AST__BAD ; + +/* Get a pointer to the current Frame from the Plot. */ + frame = astGetFrame( this, AST__CURRENT ); + +/* Initialise a flag to indicate that all adjacent labels are different. */ + ok = 0; + +/* Initialise the pointer to the list of formatted tick mark values to + indicate that no memory has yet been obtained. */ + labels = NULL; + +/* Initialise the pointer to a copy of the used format string to indicate + that no memory has yet been obtained. */ + used_fmt = NULL; + +/* Get a pointer to the axis. */ + ax = astGetAxis( frame, axis ); + +/* See if a value has been set for the axis Format. */ + fmtset = astTestFormat( frame, axis ); + +/* Get an initial set of tick mark values. This also establishes defaults for + LogTicks and LogLabel attributes, and so must be done before the + following block which uses the LogLabel attribute. */ + used_gap = GetTicks( this, axis, cen, &ticks, &nmajor, &minticks, &nminor, + fmtset, inval, &refval, pstatics, method, class, status ); + +/* See if exponential labels using superscript powers are required. */ + old_format = NULL; + reset_fmt = 0; + if( astGetLogLabel( this, axis ) && astGetEscape( this ) && + GCap( this, GRF__SCALES, 1, status ) ) { + +/* Save a copy of the Frame's Format value, if set. It will be + re-instated at the end of this function. */ + if( fmtset ) { + fmt = astGetFormat( frame, axis ); + old_format = astStore( NULL, (void *) fmt, strlen(fmt) + 1 ); + } + +/* Temporarily use a format of "%&g" to get "10**x" style axis labels, + with super-scripted "x". */ + astSetFormat( frame, axis, "%&g" ); + +/* Not all subclasses of Frame support this format specifier, so format a + test value, and see if it has two fields, the first of which is "10". + If not, we cannot use log labels so re-instate the original format. */ + nf = astFields( frame, axis, "%&g", astFormat( frame, axis, 1.0E4 ), + MAXFLD, fields, nc, &junk ); + if( nf != 2 || nc[ 0 ] != 2 || strncmp( fields[ 0 ], "10", 2 ) ) { + if( old_format ) { + astSetFormat( frame, axis, old_format ); + old_format = astFree( old_format); + } else { + astClearFormat( frame, axis ); + } + +/* If the "%&g" format is usable, note that we should reset the Format + back to its original state before leaving this function. */ + } else { + reset_fmt = 1; + } + } + +/* If a value has been set for the axis Format, see if the format string + contains a wildcard precision specifier ".*". If so, we are free to + vary the number of digits used in the label in order to produce + distinct labels. If no value has been set for the axis Format, we are + also free to vary the number of digits. */ + digset = 0; + if( fmtset ) { + fmt = astGetFormat( frame, axis ); + if( fmt ) { + digset = 1; + a = fmt; + while( (a = strchr( a, '.' )) ){ + if( *(++a) == '*' ) { + digset = 0; + break; + } + } + } + } + +/* If the axis precision has been specified, either through the Format string + or Digits value, or the Frame Digits value, we should use it so that the + user's attempts to get a specific result are not foiled. */ + if( digset || astTestAxisDigits( ax ) || astTestDigits( frame ) ){ + +/* Reserve memory to hold pointers to the formatted labels. */ + labels = (char **) astMalloc( sizeof(char *)*(size_t)nmajor ); + +/* Format the labels. We do not check that all adjacent labels are distinct + in order not to foil the users choice of format. That is, "ok" is set + non-zero by the call to CheckLabels, even if some identical adjacent + labels are found. */ + ok = CheckLabels( this, frame, axis, ticks, nmajor, 1, labels, refval, status ); + +/* Note the format used. */ + fmt = astGetFormat( frame, axis ); + if( fmt ) used_fmt = (char *) astStore( used_fmt, (void *) fmt, strlen( fmt ) + 1 ); + +/* If no precision has been specified for the axis, we need to find a + Digits value which gives different labels, but without using any more + digits than necessary. */ + } else if( astOK ){ + +/* Reserve memory to hold pointers to an initial set of labels formatted + with the default digits value. */ + labels = (char **) astMalloc( sizeof(char *)*(size_t)nmajor ); + +/* Produce these default labels. */ + CheckLabels( this, frame, axis, ticks, nmajor, 1, labels, refval, status ); + +/* The first task is to decide what the smallest usable number of digits + is. Starting at the default number of digits used above to produce the + default labels, we reduce the number of digits until one or more of the + formatted labels *increases* in length. This can happen for instance if + printf decides to include an exponent in the label. The *absolute* + minimum value 1. Set this first. */ + bot_digits = 1; + oldlabels = labels; + for( digits = astGetDigits( frame ) - 1; digits > 0; digits-- ){ + astSetAxisDigits( ax, digits ); + +/* CheckLabels2 formats the labels with the decreased number of digits, + and compares them with the old labels in "labels". If any of the new labels + are longer than the corresponding old labels, then a null pointer is + returned. Otherwise, a pointer is returned to the new set of labels. */ + newlabels = CheckLabels2( this, frame, axis, ticks, nmajor, + oldlabels, refval, status ); + +/* Free the old labels unless they are the orignal labels (which are + needed below). */ + if( oldlabels != labels ) { + for( i = 0; i < nmajor; i++ ){ + if( oldlabels[ i ] ) oldlabels[ i ] = (char *) astFree( (void *) oldlabels[ i ] ); + } + oldlabels = (char **) astFree( (void *) oldlabels ); + } + +/* If any of the labels got longer as a result of reducing the digits + value, then use the previous number of digits as the lowest possible + number of digits. Break out of the loop. */ + if( !newlabels ) { + bot_digits = digits + 1; + break; + } + +/* If none of the labels got longer, we arrive here. Use the shorter labels + for the next pass round this loop. */ + oldlabels = newlabels; + } + +/* Free any remaining labels. */ + if( oldlabels && oldlabels != labels ) { + for( i = 0; i < nmajor; i++ ){ + if( oldlabels[ i ] ) oldlabels[ i ] = (char *) astFree( (void *) oldlabels[ i ] ); + } + oldlabels = (char **) astFree( (void *) oldlabels ); + } + +/* Now loop round increasing the number of digits in the formatted labels + from the lowest usable value found above until all adjacent labels are + different. An arbitrary upper limit of 1000 is used for Digits to stop it + looping for ever. */ + for( digits = bot_digits; digits < 1000; digits++ ){ + +/* Store the new Digits value. */ + astSetAxisDigits( ax, digits ); + +/* Free memory used to hold the current set of labels. A new set will be + created by the following call to CheckLabels. */ + if( labels ) { + for( i = 0; i < nmajor; i++ ) labels[ i ] = astFree( labels[ i ] ); + } + +/* Break out of the loop if a Digits value has been found which results + in all adjacent labels being different. Note the format used (we know + the Format attribute is currently unset, but the default Format string + reflects the current value of the Digits attribute). */ + if( CheckLabels( this, frame, axis, ticks, nmajor, 0, labels, refval, status ) ) { + ok = 1; + fmt = astGetFormat( frame, axis ); + used_fmt = (char *) astStore( NULL, (void *) fmt, strlen( fmt ) + 1 ); + break; + } + } + +/* Clear the Digits value. */ + astClearAxisDigits( ax ); + } + +/* Annul the pointer to the Axis. */ + ax = astAnnul( ax ); + +/* Re-instate the original format specifier if required. */ + if( reset_fmt ) { + if( old_format ) { + astSetFormat( frame, axis, old_format ); + old_format = astFree( old_format); + } else { + astClearFormat( frame, axis ); + } + } + +/* If suitable labels were found... */ + if( ok && astOK ) { + +/* Store the used gap size. */ + *gap = used_gap; + +/* If the caller has specified the number of minor tick marks to use, + use the specified value rather than the value found above. */ + if( astTestMinTick( this, axis ) ){ + nminor = astGetMinTick( this, axis ); + } + +/* Allocate memory for the returned structure. */ + ret = (TickInfo *) astMalloc( sizeof( TickInfo ) ); + +/* If the pointer can be used, store the information. */ + if( astOK ){ + ret->nmajor = nmajor; + ret->nminor = nminor; + ret->ticks = ticks; + ret->minticks = minticks; + ret->labels = labels; + ret->fmt = used_fmt; + used_fmt = NULL; + ret->start = NULL; + ret->length = NULL; + ret->nsect = 0; + ret->gap = used_gap; + } + +/* If no suitable labels were found report an error. */ + } else if( astOK ){ + if( fmtset ){ + astError( AST__PLFMT, "%s(%s): No numerical labels can be produced " + "for axis %d using the supplied %s format string '%s'.", status, + method, class, axis + 1, astGetClass( frame ), + astGetFormat( frame, axis ) ); + } else { + astError( AST__PLFMT, "%s(%s): No suitable format can be found to " + "produce numerical labels for axis %d of a %s.", status, + method, class, axis + 1, astGetClass( frame ) ); + } + } + +/* Release any remaining resources. */ + frame = astAnnul( frame ); + if( used_fmt ) used_fmt = astFree( used_fmt ); + +/* If an error has occurred, release the returned information. */ + if( !astOK ){ + ticks = (double *) astFree( (void *) ticks ); + minticks = (double *) astFree( (void *) minticks ); + if( labels ){ + for( i = 0; i < nmajor; i++ ) { + labels[ i ] = (char *) astFree( (void *) labels[ i ] ); + } + labels = (char **) astFree( (void *) labels ); + if( ret ) (void ) astFree( (void *) ret->fmt ); + } + ret = (TickInfo *) astFree( (void *) ret ); + } + +/* Return the structure. */ + return ret; + +/* Undefine local constants. */ +#undef MAXFLD + +} + +static int TraceBorder( AstPlot *this, AstMapping *map, double xlo, double xhi, + double ylo, double yhi, int dim, double tol, + int edges[ 4 ], const char *method, const char *class, + int *status ) { +/* +* Name: +* TraceBorder + +* Purpose: +* Trace the boundary between good and bad physical coordinates through a +* fine grid. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int TraceBorder( AstPlot *this, AstMapping *map, double xlo, double xhi, +* double ylo, double yhi, int dim, double tol, +* int edges[ 4 ], const char *method, const char *class, +* int *status ) { + +* Class Membership: +* Plot member function. + +* Description: +* A rectangular grid of points in graphics coords is created covering +* the region specified by (xlo,xhi,ylo,yhi), using "dim" points along +* each axis. This grid of points is converted into physical (WCS) +* coords, and a flag is associatred with each point saying whether +* the WCS coords are good or bad. The cells in this grid are then +* scanned from bottom left to top right in raster fashion (each cell +* has a grid point at each of its 4 corners). If a cell has a mix of +* bad and good corners, the good/bad boundary must pass through it. +* If the grid is sufficiently fine (as defined by "tol") then this +* function draws a single straight line through each cell as an +* approximation to the good bad boundary. This line joins the centres +* of the two cells edges through which the boundary passes (as +* indicated by the fact that one end of the edge has good WCS coords +* and the other end has bad WCS coords). If the grid is not +* sufficiently fine to meet the "tol" requirement, then this function +* is invoked recursively to draw the curve through each cell through +* which the boundary passes. + +* Parameters: +* this +* The plot. +* map +* The Graphics->WCS mapping. +* xlo +* The lower bounds on the graphics X axis of the rectangle being +* considered. +* xhi +* The upper bounds on the graphics X axis of the rectangle being +* considered. +* ylo +* The lower bounds on the graphics Y axis of the rectangle being +* considered. +* yhi +* The upper bounds on the graphics Y axis of the rectangle being +* considered. +* dim +* The number of points along one edge of the fine grid. +* tol +* The plotting tolerance. Once each cell is smaller than this +* distance (in graphics coords), the cell is drawn. Otherwise, +* this function is invoked recursively to draw the cell using a +* finer grid. +* edges +* A pointer to an array of 4 int, in which will be returned +* flags indicating if the good/bad boundary intersects any of the +* edges of the grid. These flags are stored in the order left, +* top, right, bottom. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstPointSet *pset1; + AstPointSet *pset2; + double **ptr2; + double *px1; + double *px2; + double *py1; + double *py2; + double cxhi; + double cxlo; + double cyhi; + double cylo; + double dx; + double dy; + float xc; + float yc; + int *bndry; + int *drawn; + int bad1; + int bad2; + int bad3; + int bad4; + int icell; + int icol; + int irow; + int lastcell; + int ncell; + int recurse; + int result; + int sedges[ 4 ]; + int totcells; + +/* Initialise returned edge flags */ + edges[ 0 ] = 0; + edges[ 1 ] = 0; + edges[ 2 ] = 0; + edges[ 3 ] = 0; + +/* Initialise the returned flag to indicate that no bad regions were + found. */ + result = 0; + +/* Check the global status. */ + if ( !astOK ) return result; + +/* Create a grid of graphics and WCS coords covering the specified region + of graphics coords. "ptr2" is used to access the WCS coords at each + point in the grid. */ + ptr2 = MakeGrid( this, NULL, map, 0, dim, xlo, xhi, ylo, yhi, + 2, &pset1, &pset2, 0, method, class, status ); + +/* The number of cells along each axis of the grid is one less than the + number of points. Also get the number of cells in the whole grid. */ + ncell = dim - 1; + totcells = ncell*ncell; + +/* Store the dimensions of each cell in graphics coords. */ + dx = ( xhi - xlo )/ncell; + dy = ( yhi - ylo )/ncell; + +/* Set a flag indicating if the cell size is larger than the required + plotting tolerance. If so, we will call this function recursively to + draw the curve using a finer grid. */ + recurse = ( dx > tol || dy > tol ); + +/* If we have not yet reached the plotting tolerance, allocate work arrays + with one element for each cell in the grid. */ + if( recurse ) { + bndry = astMalloc( sizeof( int )*totcells ); + drawn = astMalloc( sizeof( int )*totcells ); + } else { + bndry = NULL; + drawn = NULL; + } + +/* Check pointers can be used safely. */ + if( astOK ) { + +/* If required, initialise work arrays to hold zero. */ + if( recurse ) { + +/* Initialise "boundary passes through cell" flags to zero. */ + memset( bndry, 0, sizeof( int )*totcells ); + +/* Initialise "cell has been drawn" flags to zero. */ + memset( drawn, 0, sizeof( int )*totcells ); + } + +/* Store the Y graphics coords at the bottom and top of the first row. */ + cylo = ylo; + cyhi = ylo + dy; + +/* Store pointers to the physical coords at the bottom left corner of the + first cell in the first row. */ + px1 = ptr2[ 0 ]; + py1 = ptr2[ 1 ]; + +/* Store pointers to the physical coords at the top left corner of the + first cell in the first row. */ + px2 = px1 + dim; + py2 = py1 + dim; + +/* Store the index of the last cell in a row or column. */ + lastcell = ncell - 1; + +/* Initialise index of next cell. */ + icell = 0; + +/* Loop round every row of cells in this grid. */ + for( irow = 0; irow < ncell; irow++ ) { + +/* See if the physical coords are bad at the bottom left corner of the + first cell in this row. At the same time, increment the pointers so + they refer to the bottom right corner of the first cell in this row. */ + bad1 = ( *px1 == AST__BAD || *py1 == AST__BAD ); + +/* Increment the pointers. Do not do it in the above "if" statement since + the or (!!) means that the second expression may never be evaluated. */ + px1++; + py1++; + +/* See if the physical coords are bad at the top left corner of the + first cell in this row. At the same time, increment the pointers so + they refer to the top right corner of the first cell in this row. */ + bad2 = ( *px2 == AST__BAD || *py2 == AST__BAD ); + px2++; + py2++; + +/* Loop round every cell in the current row of cells. */ + for( icol = 0; icol < ncell; icol++, icell++ ) { + +/* See if the physical coords are bad at the bottom right corner of the + current cell in this row. At the same time, increment the pointers so + they refer to the bottom right corner of the next cell in this row. */ + bad3 = ( *px1 == AST__BAD || *py1 == AST__BAD ); + px1++; + py1++; + +/* See if the physical coords are bad at the top right corner of the + current cell in this row. At the same time, increment the pointers so + they refer to the top right corner of the next cell in this row. */ + bad4 = ( *px2 == AST__BAD || *py2 == AST__BAD ); + px2++; + py2++; + +/* Set the returned flag non-zero if any invalidpositions are found. */ + if( bad1 || bad2 || bad3 || bad4 ) result = 1; + +/* If there are a mixture of good and bad corners, the good/bad boundary + must pass through the current cell. */ + if( bad2 != bad1 || bad3 != bad1 || bad4 != bad1 ) { + +/* If we have not yet reached the required plotting tolerance, set a flag + to indicate that the boundary should be plotted through this cell + using a recirsive call to this function. */ + if( recurse ) { + bndry[ icell ] = 1; + +/* If we have reached the required plotting tolerance, draw the boundary + as a straight line between the centres of the edges through which the + boundary enteres and leaves the current cell. */ + } else { + +/* Get the upper and lower graphics X bounds of the current cell. */ + cxlo = xlo + icol*dx; + cxhi = cxlo + dx; + +/* If an edge of the current cell has good coords at one end but bad + coords at the other, the boundary is assumed to pass through the edge + at its centre. Normally, we expect only two cell edges to have this + property (i.e the boundary enters the cell through one edge and leaves + through the other). However, sometimes all four edges may have this + property. In this case, two sections of the boundary must pass through + the cell, and there is no way of knowing which edges connect together + (short of further recursion), and we arbitrarily decide to join opposite + edges. */ + if( bad1 == bad4 && bad2 == bad3 ) { + +/* Draw a horizontal line through the cell centre */ + yc = 0.5*( cylo + cyhi ); + Bpoly( this, (float) cxlo, yc, status ); + Apoly( this, (float) cxhi, yc, status ); + +/* Draw a vertical line through the cell centre */ + xc = 0.5*( cxlo + cxhi ); + Bpoly( this, xc, (float) cylo, status ); + Apoly( this, xc, (float) cyhi, status ); + +/* If the boundary passes through the left hand edge, it must also have + passed through the right edge of the previous cell in the row (unless + this is the first cell in the row), so we do not need to begin a new + polyline (we can just extend the existing polyline). */ + } else if( bad1 != bad2 ) { + +/* If this is the first cell in the row, begin a new polyline. */ + yc = 0.5*( cylo + cyhi ); + if( icol == 0 ) Bpoly( this, (float) cxlo, yc, status ); + +/* and through the top edge, draw a line between the centres of the left + and top edges. */ + if( bad2 != bad4 ) { + xc = 0.5*( cxlo + cxhi ); + Apoly( this, xc, (float) cyhi, status ); + +/* or through the right edge, draw a line between the centres of the left + and right edges. */ + } else if( bad3 != bad4 ) { + Apoly( this, (float) cxhi, yc, status ); + +/* Otherwise, draw a line between the centres of the left and bottom edges. */ + } else { + xc = 0.5*( cxlo + cxhi ); + Apoly( this, xc, (float) cylo, status ); + } + +/* If the boundary passes through the top edge (we do not need to check + the left edge because that was done above)... */ + } else if( bad4 != bad2 ) { + +/* and through the right edge, draw a line between the centres of the top + and right edges. */ + if( bad3 != bad4 ) { + xc = 0.5*( cxlo + cxhi ); + yc = 0.5*( cylo + cyhi ); + Bpoly( this, xc, (float) cyhi, status ); + Apoly( this, (float) cxhi, yc, status ); + +/* Otherwise, draw a line between the centres of the top and bottom edges. */ + } else { + xc = 0.5*( cxlo + cxhi ); + Bpoly( this, xc, (float) cyhi, status ); + Apoly( this, xc, (float) cylo, status ); + } + +/* If the boundary passes through the right edge it must also pass + throught the bottom edge since all other combinations will have been + trapped above. */ + } else { + xc = 0.5*( cxlo + cxhi ); + yc = 0.5*( cylo + cyhi ); + Bpoly( this, xc, (float) cylo, status ); + Apoly( this, (float) cxhi, yc, status ); + } + +/* If the current cell is on the edge of the grid, set flags in the + returned "edges" array to indicate that the boundary passes out of + the grid on the appropriate edge. */ + if( icol == 0 ) { + if( bad1 != bad2 ) edges[ 0 ] = 1; /* Left edge */ + } else if( icol == lastcell ) { + if( bad3 != bad4 ) edges[ 2 ] = 1; /* Right edge */ + } + + if( irow == 0 ) { + if( bad1 != bad3 ) edges[ 3 ] = 1; /* Bottom edge */ + } else if( irow == lastcell ) { + if( bad2 != bad4 ) edges[ 1 ] = 1; /* Top edge */ + } + } + } + +/* The flags for the right hand corners of the current cell can be + re-used as the flags for the left hand corners of the next cell. */ + bad1 = bad3; + bad2 = bad4; + } + +/* Store the Y graphics coords at the bottom and top of the next row. */ + cylo = cyhi; + cyhi = cylo + dy; + } + +/* If we have not yet reached the required plotting tolerance, call this + function recursively to draw the boundary through the cells identified + above. On each pass through this loop, we may discover more boundary + cells in the grid, in addition to those found above. Continue looping + until no further boundary cells are found. */ + while( recurse ) { + +/* Assume that the current pass though this loop will result in all boundary + cells being draw, in which case we can then leave the loop. */ + recurse = 0; + +/* Store the Y graphics coords at the bottom and top of the first row. */ + cylo = ylo; + cyhi = ylo + dy; + +/* Initialise the cell index */ + icell = 0; + +/* Loop round every row of cells in this grid. */ + for( irow = 0; irow < ncell; irow++ ) { + +/* Loop round every cell in the current row of cells. */ + for( icol = 0; icol < ncell; icol++, icell++ ) { + +/* If the good/bad boundary passes through the current cell we need to + draw it unless it has already been drawn. */ + if( bndry[ icell ] && ! drawn[ icell ] ){ + +/* Get the upper and lower graphics X bounds of the current cell. */ + cxlo = xlo + icol*dx; + cxhi = cxlo + dx; + +/* Call this function recursively to draw the boundary through the current + cell, setting the returned flag non-zero if any bad positions are found. */ + if( TraceBorder( this, map, cxlo, cxhi, cylo, cyhi, 3, tol, + sedges, method, class, status ) ) result = 1; + +/* The boundary may have passed out of the current cell and then back + into the cell on the same edge (i.e. a small loop that pokes out into + a neighbouring cell). Such neighbouring cells may not have been + identified by the earlier section of this function, so we now ensure + that any such cells are flagged as boundary cells. */ + +/* If the boundary passed out of the left edge of the cell... */ + if( sedges[ 0 ] ) { + +/* If the current cell is at the left edge of the grid, indicate that the + boundary passes out of the left edge of the grid. */ + if( icol == 0 ) { + edges[ 0 ] = 1; /* Left edge */ + +/* Otherwise, if the left hand neighbour of the current cell is not + flagged as a boundary cell, flag it now and indicate that another pass + though the loop is needed to draw the extra cell. */ + } else if( ! bndry[ icell - 1 ] ) { + bndry[ icell - 1 ] = 1; + recurse = 1; + } + } + +/* If the boundary passed out of the top edge of the cell... */ + if( sedges[ 1 ] ) { + +/* If the current cell is at the top edge of the grid, indicate that the + boundary passes out of the top edge of the grid. */ + if( irow == lastcell ) { + edges[ 1 ] = 1; /* Top edge */ + +/* Otherwise, ensure that the upper neighbour of the current cell is + flagged as a boundary cell. */ + } else { + bndry[ icell + ncell ] = 1; + } + } + +/* If the boundary passed out of the right edge of the cell... */ + if( sedges[ 2 ] ) { + +/* If the current cell is at the right edge of the grid, indicate that the + boundary passes out of the right edge of the grid. */ + if( icol == lastcell ) { + edges[ 2 ] = 1; /* Right edge */ + +/* Otherwise, ensure that the right hand neighbour of the current cell is + flagged as a boundary cell. */ + } else { + bndry[ icell + 1 ] = 1; + } + } + +/* If the boundary passed out of the bottom edge of the cell... */ + if( sedges[ 3 ] ) { + +/* If the current cell is at the bottom edge of the grid, indicate that the + boundary passes out of the bottom edge of the grid. */ + if( irow == 0 ) { + edges[ 3 ] = 1; /* Bottom edge */ + +/* Otherwise, if the lower neighbour of the current cell is not flagged + as a boundary cell, flag it now and indicate that another pass though + the loop is needed to draw the extra cell. */ + } else if( ! bndry[ icell - ncell ] ) { + bndry[ icell - ncell ] = 1; + recurse = 1; + } + } + +/* Indicate this cell has been drawn. */ + drawn[ icell ] = 1; + } + } + +/* Store the Y graphics coords at the bottom and top of the next row. */ + cylo += dy; + cyhi = cylo + dy; + } + } + } + +/* Free resources */ + bndry = astFree( bndry ); + drawn = astFree( drawn ); + pset1 = astAnnul( pset1 ); + pset2 = astAnnul( pset2 ); + +/* Return the result. */ + return result; +} + +static AstPointSet *Trans( AstPlot *this, AstFrame *frm, AstMapping *mapping, + AstPointSet *in, int forward, AstPointSet *out, + int norm, const char *method, const char *class, int *status ) { +/* +* Name: +* Trans + +* Purpose: +* Use a Mapping to transform a set of points. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* AstPointSet *Trans( AstPlot *this, AstFrame *frm, AstMapping *mapping, +* AstPointSet *in, int forward, AstPointSet *out, +* int norm, const char *method, const char *class ) + +* Class Membership: +* Plot member function. + +* Description: +* This performs the same task as the protected method astTransform +* but uses the astTransform method for the supplied Mapping instead +* the parent method for the Plot. This allows the Mapping to be +* extracted from the Plot using astGetMapping once, rather than every +* time a mapping is performed. + +* Parameters: +* this +* Pointer to the Plot (only used to access clipping attributes and +* other methods). +* frm +* Pointer to the Current Frame in the Plot. If this is NULL, then +* a pointer for the Current Frame is found within this function if +* required (i.e. if "forward" and "norm" are both non-zero). +* mapping +* Pointer to the Mapping extracted from the Plot. If this is NULL, then +* a pointer for the base->current Mapping is found within this function. +* in +* Pointer to the PointSet holding the input coordinate data. +* forward +* A non-zero value indicates that the forward coordinate +* transformation should be applied while a zero value requests the +* inverse transformation. +* out +* Pointer to a PointSet which will hold the transformed (output) +* coordinate values. A NULL value may also be given, in which case a +* new PointSet will be created by this function. +* norm +* The normalisation of returned physical coordinates is only done +* if "norm" is non-zero. Otherwise they are left as returned by +* astTransform. +* method +* Pointer to a string holding the name of the calling method. +* This is only for use in constructing error messages. +* class +* Pointer to a string holding the name of the supplied object class. +* This is only for use in constructing error messages. + +* Returned Value: +* Pointer to the output (possibly new) PointSet. + +* Notes: +* - Clipping is only performed as set up using the astClip method. +* In particular, the clipping specified by the arguments to the astPlot +* constructor function is NOT performed. This is done in order to improve +* the efficiency of the curve drawing method astGridLine. +* - A null pointer will be returned if this function is invoked with the +* global error status set, or if it should fail for any reason. +* - The number of coordinate values per point in the input PointSet must +* match the number of coordinates for the Plot being applied. +* - If an output PointSet is supplied, it must have space for sufficient +* number of points and coordinate values per point to accommodate the +* result. Any excess space will be ignored. +*/ + +/* Local Variables: */ + AstFrame *cfr; /* Pointer to the Current Frame */ + AstFrame *fr; /* Pointer to the clipping Frame */ + AstMapping *map; /* Pointer to output->clip mapping */ + AstPointSet *clip; /* Positions in clipping Frame */ + AstPointSet *result; /* Positions in output Frame */ + double **ptr_clip; /* Pointer to clipping Frame data */ + double **ptr_out; /* Pointer to output coordinate data */ + double *work; /* Pointer to array holding an o/p position */ + double axval; /* Axis value in clipping frame */ + double lbnd; /* Lower bound on current clipping axis */ + double ubnd; /* Upper bound on current clipping axis */ + int axin; /* Is the axis value within the allowed range? */ + int clip_norm; /* Normalise the clipping positions? */ + int clip_or; /* Combine axes using a logical OR? */ + int clipit; /* Should the current point be clipped? */ + int i; /* Point index */ + int iframe; /* Validated index for clipping Frame */ + int j; /* Axis index */ + int naxes; /* Number of axes in clipping Frame */ + int ncoord_out; /* Number of coordinates per output point */ + int npoint; /* Number of points */ + +/* Check the global error status. */ + if ( !astOK ) return NULL; + +/* Ensure we have a Mapping */ + if( !mapping ) mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); + +/* Apply the parent mapping using the stored pointer to the Transform member + function inherited from the parent FrameSet class. */ + result = astTransform( mapping, in, forward, out ); + +/* Get the dimensions of the returned data, and an array of pointers to + the axis values. */ + ncoord_out = astGetNcoord( result ); + npoint = astGetNpoint( result ); + ptr_out = astGetPoints( result ); + +/* If we have done a forward mapping, we now normalise the returned physical + positions if required using the astNorm method for the supplied object. */ + if( forward && norm ){ + +/* If no Frame was supplied, get a pointer to the Current Frame. Otherwise, + use the supplied pointer. */ + if( !frm ) { + cfr = astGetFrame( this, AST__CURRENT ); + } else { + cfr = frm; + } + +/* Get work space to hold a single positions. */ + work = (double *) astMalloc( sizeof(double)*(size_t)ncoord_out ); + +/* Check the work space and axis pointers can be used. */ + if( astOK ){ + +/* Now loop through every position, copying the axis values to the work array, + normalising them using astNorm, and copying them back to the returned + PointSet. */ + for( i = 0; i < npoint; i++ ){ + for( j = 0; j < ncoord_out; j++ ) work[ j ] = ptr_out[ j ][ i ]; + astNorm( cfr, work ); + for( j = 0; j < ncoord_out; j++ ) ptr_out[ j ][ i ] = work[ j ]; + } + } + +/* Free the work space. */ + work = (double *) astFree( (void *) work ); + +/* Annul the pointer to the Current Frame if it was obtained in this + function. */ + if( !frm ) cfr = astAnnul( cfr ); + + } + +/* Clipping is only performed if the bounds of a clipping region are + available for both axes. */ + if( this->clip_lbnd && this->clip_ubnd ){ + +/* Validate and translate the index of the clipping Frame. */ + iframe = astValidateFrameIndex( this, this->clip_frame, method ); + +/* Obtain a pointer to the clipping Frame and determine how many axes it + has. */ + fr = astGetFrame( this, iframe ); + naxes = astGetNaxes( fr ); + +/* Report an error if the number of bounds does not equal the number of + axes in the clipping Frame. */ + if( astOK && naxes != this->clip_axes ){ + astError( AST__CLPAX, "%s%s): The supplied %s specifies clipping " + "in %d dimensions, but the clipping Frame ('%s') has " + "%d axes.", status, method, class, class, this->clip_axes, + astGetTitle( fr ), naxes ); + } + +/* Set a flag indicating if the coordinates in the clipping frame need to + be normalised. */ + clip_norm = 1; + +/* We now obtain a pointer to a PointSet holding the corresponding + coordinates in the clipping frame. If the clipping frame is the + base frame, then take a clone of the PointSet holding base frame + coordinates. */ + if( iframe == astGetBase( this ) ){ + if( forward ){ + clip = astClone( in ); + } else { + clip = astClone( result ); + } + +/* If the clipping frame is the current frame, then take a clone of the + PointSet holding current coordinates. Note, if the returned physical + coordinates have already been normalised, we don't need to normalise + the clipping coordinates. */ + } else if( iframe == astGetCurrent( this ) ){ + if( forward ){ + clip = astClone( result ); + if( norm ) clip_norm = 0; + } else { + clip = astClone( in ); + } + +/* If the clipping Frame is neither the base nor the current Frame, we need + to map the returned normalised points into the clipping Frame. */ + } else { + if( forward ){ + map = astGetMapping( this, AST__CURRENT, iframe ); + } else { + map = astGetMapping( this, AST__BASE, iframe ); + } + clip = astTransform( map, result, 1, NULL ); + map = astAnnul( map ); + } + +/* Get a pointer to the coordinate data in the clipping Frame. */ + ptr_clip = astGetPoints( clip ); + +/* If necessary, normalise the coordinates in the clipping frame. */ + if( clip_norm ){ + +/* Get work space to hold a single position. */ + work = (double *) astMalloc( sizeof(double)*(size_t)naxes ); + +/* Check the work space and axis pointers can be used. */ + if( astOK ){ + +/* Now loop through every position, copying the axis values to the work array, + normalising them using astNorm, and copying them back to the clipping + PointSet. */ + for( i = 0; i < npoint; i++ ){ + for( j = 0; j < naxes; j++ ) work[ j ] = ptr_clip[ j ][ i ]; + astNorm( fr, work ); + for( j = 0; j < naxes; j++ ) ptr_clip[ j ][ i ] = work[ j ]; + } + } + +/* Free the work space. */ + work = (double *) astFree( (void *) work ); + + } + +/* If all has gone ok, we will now clip the returned points. */ + if( astOK ){ + +/* Get the logical operation to be used to determine if a point is to be + clipped. A zero value means that a logical AND is to be performed + between the axes (i.e. all axes must be within the supplied bounds for a + point to be retained). A non-zero value means that a logical OR is to be + performed between the axes (i.e. only a single axis need be within the + supplied bounds for a point to be retained). */ + clip_or = astGetClipOp( this ); + +/* Do each point in turn. */ + for( j = 0; j < npoint; j++ ){ + +/* If all axes must fall within the supplied range to avoid the point being + clipped (i.e. if clip_or is 0), then assume initially that the point + is not to be clipped. This will be toggled as soon as the first + out-of-bounds point is found. If, on the other hand, the point is + only clipped if all axis values are out-of-bounds, then assume + initially that the point is to be clipped. This will be toggled as + soon as the first axis value is found which is not out-of-bounds. */ + clipit = clip_or; + +/* Check each axis value for the current point. */ + for( i = 0; i < naxes; i++ ){ + axval = ptr_clip[ i ][ j ]; + +/* Chekc that it is not bad. */ + if( axval != AST__BAD ){ + +/* Store the bounds of the clipping volume on this axis. */ + lbnd = this->clip_lbnd[ i ]; + ubnd = this->clip_ubnd[ i ]; + +/* Set a flag indicating if the axis value is within the specified range. + If the supplied bounds are reversed, they specify the range to exclude, + otherwise they specify the range to include. */ + if( lbnd <= ubnd ){ + axin = ( axval >= lbnd && axval <= ubnd ); + } else { + axin = ( axval < ubnd || axval > lbnd ); + } + +/* If the point is within the range and only one such point is + required to avoid the point being clipped, indicate that the point + should not be clipped, and leave the loop. */ + if( axin && clip_or ){ + clipit = 0; + break; + +/* If the point is not within the range and we only one such point is + required to cause the point to be clipped, indicate that the point + should be clipped, and leave the loop. */ + } else if( !axin && !clip_or ){ + clipit = 1; + break; + } + +/* Clip the point if any axis value is bad in the clipping Frame. */ + } else { + clipit = 1; + break; + } + + } + +/* If the point is to be clipped, set all returned axis values bad. */ + if( clipit ) { + for( i = 0; i < naxes; i++ ) ptr_out[ i ][ j ] = AST__BAD; + } + + } + + } + +/* Annul the PointSet holding clipping Frame positions. */ + if( clip ) clip = astAnnul( clip ); + +/* Annul the clipping Frame pointer. */ + fr = astAnnul( fr ); + + } + +/* If an error has occurred, annul the result. */ + if( !astOK ) result = astAnnul( result ); + +/* Return a pointer to the output PointSet. */ + return result; + +} + +static AstPointSet *Transform( AstMapping *this, AstPointSet *in, + int forward, AstPointSet *out, int *status ) { +/* +* Name: +* Transform + +* Purpose: +* Use a Plot to transform a set of points. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* AstPointSet *Transform( AstMapping *this, AstPointSet *in, +* int forward, AstPointSet *out ) + +* Class Membership: +* Plot member function (over-rides the astTransform protected +* method inherited from the FrameSet class). + +* Description: +* This function takes a Plot and a set of points encapsulated in a +* PointSet and transforms the points from graphics coordinates to +* physical coordinates (in the forward direction). If the returned +* positions are physical coordinates (i.e. if a forward mapping is +* performed) they are normalised using the astNorm method of the supplied +* Plot. The returned axis values are set to AST__BAD for any positions +* which are outside the clipping volume set up by the astClip method. + +* Parameters: +* this +* Pointer to the Plot. +* in +* Pointer to the PointSet holding the input coordinate data. +* forward +* A non-zero value indicates that the forward coordinate +* transformation should be applied while a zero value requests the +* inverse transformation. +* out +* Pointer to a PointSet which will hold the transformed (output) +* coordinate values. A NULL value may also be given, in which case a +* new PointSet will be created by this function. + +* Returned Value: +* Pointer to the output (possibly new) PointSet. + +* Notes: +* - Clipping is only performed as set up using the astClip method. +* In particular, the clipping specified by the arguments to the astPlot +* constructor function is NOT performed. This is done in order to improve +* the efficiency of the curve drawing method astGridLine. +* - A null pointer will be returned if this function is invoked with the +* global error status set, or if it should fail for any reason. +* - The number of coordinate values per point in the input PointSet must +* match the number of coordinates for the Plot being applied. +* - If an output PointSet is supplied, it must have space for sufficient +* number of points and coordinate values per point to accommodate the +* result. Any excess space will be ignored. +*/ + +/* Local Variables: */ + AstMapping *map; /* Pointer to the mapping */ + AstPointSet *result; /* Positions in output Frame */ + AstPlot *plot; /* The Plot */ + +/* Check the global error status. */ + if ( !astOK ) return NULL; + +/* Get a pointer to the Plot. */ + plot = (AstPlot *) this; + +/* Get the Mapping from the base to the current Frame. */ + map = astGetMapping( plot, AST__BASE, AST__CURRENT ); + +/* Do the transformation. */ + result = Trans( plot, NULL, map, in, forward, out, 1, "astTransform", + astGetClass( this ), status ); + +/* Annul the mapping. */ + map = astAnnul( map ); + +/* If an error has occurred, annul the result. */ + if( !astOK ) result = astAnnul( result ); + +/* Return a pointer to the output PointSet. */ + return result; + +} + +static double Typical( int n, double *value, double lolim, double hilim, + double *width, int *status ) { +/* +* Name: +* Typical + +* Purpose: +* Return a typical value within the supplied array of values. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* double Typical( int n, double *value, double lolim, double hilim, +* double *width, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This function locates the approximate mode of the supplied values, +* and returns one of the supplied values which is close to the modal +* value. Values outside an indicated range are ignored. + +* Parameters: +* n +* The number of data values. +* value +* A pointer to an array of "n" values. +* lolim +* Values less than lolim are ignored. Supply as -DBL_MAX if there +* is no lower limit. +* hilim +* Values greater than hilim are ignored. Supply as DBL_MAX if there +* is no upper limit. +* width +* Pointer to a double in which to return the width (i,e, data range) +* of the non-empty histogram cells. This is an estimate of the +* range of used values in the supplied array. NULL may be supplied. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A typical value from the supplied array. AST__BAD is returned only +* if an error has occurred, or if all the supplied values are AST__BAD +* or outside the specified range. + +*/ + +/* Local Variables: */ + double *a; /* Pointer to next value */ + double cnt; /* Modified count */ + double delta; /* Bin size */ + double maxval; /* Maximum supplied value */ + double mean; /* Mean supplied value */ + double minval; /* Minimum supplied value */ + double result; /* The returned value. */ + double w0; /* Rate of increase of weight with dist from edge */ + double w1; /* Weight for left edge */ + double w2; /* Weight for right edge */ + double w; /* Weight for this bin */ + int *hist; /* Pointer to first cell of histogram array */ + int i; /* Loop count */ + int ibin; /* Bin index */ + int maxcnt; /* Maximum no. of values in any bin */ + int modify; /* Modify the effect of the edge bins? */ + int nbin; /* No. of bins in histogram */ + int nc; /* Total number of points in histogram */ + int ngood; /* No. of good values supplied */ + int nonemp; /* No. of non-empty bins in hstogram */ + +/* Initialise. */ + result = AST__BAD; + if( width ) *width = 0.0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + ibin = 0; + +/* Find the minimum and maximum value in the supplied array, which are + also within the supplied limits. Also store the first good value + encountered in "result". */ + minval = DBL_MAX; + maxval = -DBL_MAX; + a = value; + ngood = 0; + for( i = 0; i < n; i++, a++ ) { + if( *a != AST__BAD ) { + if( *a >= lolim && *a <= hilim ) { + if( *a < minval ) minval = *a; + if( *a > maxval ) maxval = *a; + if( ngood == 0 ) result = *a; + ngood++; + } + } + } + +/* Initialise the returned width to the total data range. */ + if( width && maxval != -DBL_MAX ) *width = maxval - minval; + +/* If less than 3 points were found, we will return the first. Otherwise, if + 3 or more good values were found, find a typical value. */ + if( ngood > 2 ) { + +/* We will form a histogram of the supplied values in order to find the + mode. The number of bins in this histogram is chosen so that there + is an average of 2 points per bin. Find the number of bins. */ + nbin = ( ngood + 1 )/2; + +/* Find the bin size. If zero (i.e. if all values are equal), return the + first good value established above. */ + delta = ( maxval - minval )/ nbin; + if( delta > 0.0 ) { + +/* Allocat ememory for the histogram. */ + hist = astMalloc( sizeof(int)*(size_t)nbin ); + if( hist ) { + +/* Initialise the histogram. */ + for( i = 0; i < nbin; i++ ) hist[ i ] = 0; + +/* Form the histogram. Form the mean data value at the same time. */ + mean = 0.0; + a = value; + nc = 0; + for( i = 0; i < n; i++, a++ ){ + if( *a != AST__BAD ) { + if( *a >= lolim && *a <= hilim ) { + mean += *a; + ibin = (int) ( ( *a - minval )/ delta ); + if( ibin == nbin ) ibin--; + hist[ ibin ]++; + nc++; + } + } + } + + mean /= ngood; + +/* We tend to prefer not to use reference values which are very close the + the limits since they can give problems with regard to normalization + (rounding errors can knock them over the edge), so we modify the counts + in each bin of the histogram to reduce the impact of bins near the edge. + However, we do not do this if the number of bins is very small or if + all the counts are in the edge bins. */ + modify = ( nbin > 4 && + ( hist[ 0 ] + hist[ nbin - 1 ] < 0.98*ngood ) ); + +/* Find the bin with the highest modified count. If there is more than one bin + with the highest modified count, choose the one which is closest to the + mean data value found above. Also count the number of non-empty bins. */ + nonemp = 0; + maxcnt = 0; + w0 = nbin/2; + for( i = 0; i < nbin; i++ ) { + + cnt = hist[ i ]; + if( cnt ) nonemp++; + + if( modify ) { + w1 = i*w0; + w2 = ( nbin - 1 - i )*w0; + w = ( w1 < w2 ) ? w1 :w2; + if( w < 1.0 ) cnt *= w; + } + + if( cnt > maxcnt ) { + maxcnt = cnt; + ibin = i; + + } else if( cnt == maxcnt ) { + if( fabs( minval + ( i - 0.5 )*delta - mean ) < + fabs( minval + ( ibin - 0.5 )*delta - mean ) ) { + maxcnt = cnt; + ibin = i; + } + } + } + +/* Free the histogram memory. */ + hist = astFree( hist ); + +/* If required, return the width of the non-empty bins. */ + if( width ) *width = nonemp*delta; + +/* Call this function recursively to refine the value, restricting + attention to those data values which are within the range of the bin + found above. */ + if( maxcnt < nc && ibin*delta > 1000.0*DBL_EPSILON*fabs(maxval) ) { + minval += ibin*delta; + maxval = minval + delta; + result = Typical( n, value, minval, maxval, NULL, status ); + } + } + } + } + +/* Return the result. */ + return result; +} + +static int GetUseColour( AstPlot *this, int id, int *status ) { +/* +* Name: +* GetUseColour + +* Purpose: +* Get the Colour value to use for a specified graphical element. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int GetUseColour( AstPlot *this, int id, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This returns the Colour value for the graphical element specified by +* id. If an element related to a generic value is being accessed (e.g +* "Axes" is generic, "Axis1" and "Axis2" are not), then the colour +* for the first set specific value is returned. For example, if the +* Colour for AST__AXES_ID is requested, then the colour for AST__AXIS1_ID +* will be returned if set, and otherwise the colour for AST__AXIS2_ID will +* be returned. If AST__AXIS2_ID is not set either, then the default for +* AST__AXIS2_ID will be returned. + +* Parameters: +* this +* Pointer to the Plot. +* id +* An integer specifying the graphical element to be drawn. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Colour value to use. + +*/ + +/* Local Variables: */ + int id1; /* First genuine identifier */ + int id2; /* Second genuine identifier */ + int id3; /* Third genuine identifier */ + int nid; /* Number of genuine attributes */ + +/* Check the global error status. */ + if ( !astOK ) return NOCOLOUR; + +/* See if the supplied identifier is a psuedo-identifier representing two + or three other genuine identifiers. If so, return the value of the first + set genuine identifier. */ + nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); + if( nid > 1 ) { + if( astTestColour( this, id1 ) ) { + id = id1; + + } else if( nid > 1 && astTestColour( this, id2 ) ) { + id = id2; + + } else if( nid > 2 && astTestColour( this, id3 ) ) { + id = id3; + + } else { + id = id1; + } + } + +/* Return the result. */ + return astGetColour( this, id ); + +} + +static int GetUseFont( AstPlot *this, int id, int *status ) { +/* +* Name: +* GetUseFont + +* Purpose: +* Get the Font value to use for a specified graphical element. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int GetUseFont( AstPlot *this, int id, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This returns the Font value for the graphical element specified by +* id. If an element related to a generic value is being accessed (e.g +* "Axes" is generic, "Axis1" and "Axis2" are not), then the Font +* for the first set specific value is returned. For example, if the +* Font for AST__AXES_ID is requested, then the Font for AST__AXIS1_ID +* will be returned if set, and otherwise the Font for AST__AXIS2_ID will +* be returned. If AST__AXIS2_ID is not set either, then the default for +* AST__AXIS2_ID will be returned. + +* Parameters: +* this +* Pointer to the Plot. +* id +* An integer specifying the graphical element to be drawn. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Font value to use. + +*/ + +/* Local Variables: */ + int id1; /* First genuine identifier */ + int id2; /* Second genuine identifier */ + int id3; /* Third genuine identifier */ + int nid; /* Number of genuine attributes */ + +/* Check the global error status. */ + if ( !astOK ) return NOFONT; + +/* See if the supplied identifier is a psuedo-identifier representing two + or three other genuine identifiers. If so, return the value of the first set + genuine identifier. */ + nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); + if( nid > 1 ) { + if( astTestFont( this, id1 ) ) { + id = id1; + + } else if( nid > 1 && astTestFont( this, id2 ) ) { + id = id2; + + } else if( nid > 2 && astTestFont( this, id3 ) ) { + id = id3; + + } else { + id = id1; + } + } + +/* Return the result. */ + return astGetFont( this, id ); + +} + +static double GetUseSize( AstPlot *this, int id, int *status ) { +/* +* Name: +* GetUseSize + +* Purpose: +* Get the Size value to use for a specified graphical element. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* double GetUseSize( AstPlot *this, int id, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This returns the Size value for the graphical element specified by +* id. If an element related to a generic value is being accessed (e.g +* "Axes" is generic, "Axis1" and "Axis2" are not), then the Size +* for the first set specific value is returned. For example, if the +* Size for AST__AXES_ID is requested, then the Size for AST__AXIS1_ID +* will be returned if set, and otherwise the Size for AST__AXIS2_ID will +* be returned. If AST__AXIS2_ID is not set either, then the default for +* AXIS2_ID will be returned. + +* Parameters: +* this +* Pointer to the Plot. +* id +* An integer specifying the graphical element to be drawn. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Size value to use. + +*/ + +/* Local Variables: */ + int id1; /* First genuine identifier */ + int id2; /* Second genuine identifier */ + int id3; /* Third genuine identifier */ + int nid; /* Number of genuine attributes */ + +/* Check the global error status. */ + if ( !astOK ) return NOSIZE; + +/* See if the supplied identifier is a psuedo-identifier representing two + or three other genuine identifiers. If so, return the value of the first set + genuine identifier. */ + nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); + if( nid > 1 ) { + if( astTestSize( this, id1 ) ) { + id = id1; + + } else if( nid > 1 && astTestSize( this, id2 ) ) { + id = id2; + + } else if( nid > 2 && astTestSize( this, id3 ) ) { + id = id3; + + } else { + id = id1; + } + } + +/* Return the result. */ + return astGetSize( this, id ); + +} + +static int GetUseStyle( AstPlot *this, int id, int *status ) { +/* +* Name: +* GetUseStyle + +* Purpose: +* Get the Style value to use for a specified graphical element. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int GetUseStyle( AstPlot *this, int id, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This returns the Style value for the graphical element specified by +* id. If an element related to a generic value is being accessed (e.g +* "Axes" is generic, "Axis1" and "Axis2" are not), then the style +* for the first set specific value is returned. For example, if the +* Style for AST__AXES_ID is requested, then the style for AST__AXIS1_ID +* will be returned if set, and otherwise the style for AST__AXIS2_ID will +* be returned. If AST__AXIS2_ID is not set either, then the default for +* AST__AXIS2_ID will be returned. + +* Parameters: +* this +* Pointer to the Plot. +* id +* An integer specifying the graphical element to be drawn. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Style value to use. + +*/ + +/* Local Variables: */ + int id1; /* First genuine identifier */ + int id2; /* Second genuine identifier */ + int id3; /* Third genuine identifier */ + int nid; /* Number of genuine attributes */ + +/* Check the global error status. */ + if ( !astOK ) return NOSTYLE; + +/* See if the supplied identifier is a psuedo-identifier representing two + or three other genuine identifiers. If so, return the value of the first set + genuine identifier. */ + nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); + if( nid > 1 ) { + if( astTestStyle( this, id1 ) ) { + id = id1; + + } else if( nid > 1 && astTestStyle( this, id2 ) ) { + id = id2; + + } else if( nid > 2 && astTestStyle( this, id3 ) ) { + id = id3; + + } else { + id = id1; + } + } + +/* Return the result. */ + return astGetStyle( this, id ); + +} + +static double GetUseWidth( AstPlot *this, int id, int *status ) { +/* +* Name: +* GetUseWidth + +* Purpose: +* Get the Width value to use for a specified graphical element. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* double GetUseWidth( AstPlot *this, int id, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This returns the Width value for the graphical element specified by +* id. If an element related to a generic value is being accessed (e.g +* "Axes" is generic, "Axis1" and "Axis2" are not), then the Width +* for the first set specific value is returned. For example, if the +* Width for AST__AXES_ID is requested, then the Width for AST__AXIS1_ID +* will be returned if set, and otherwise the Width for AST__AXIS2_ID will +* be returned. If AST__AXIS2_ID is not set either, then the default for +* AST__AXIS2_ID will be returned. + +* Parameters: +* this +* Pointer to the Plot. +* id +* An integer specifying the graphical element to be drawn. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Width value to use. + +*/ + +/* Local Variables: */ + int id1; /* First genuine identifier */ + int id2; /* Second genuine identifier */ + int id3; /* Third genuine identifier */ + int nid; /* Number of genuine attributes */ + +/* Check the global error status. */ + if ( !astOK ) return NOWIDTH; + +/* See if the supplied identifier is a psuedo-identifier representing two + or three other genuine identifiers. If so, return the value of the first set + genuine identifier. */ + nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); + if( nid > 1 ) { + if( astTestWidth( this, id1 ) ) { + id = id1; + + } else if( nid > 1 && astTestWidth( this, id2 ) ) { + id = id2; + + } else if( nid > 2 && astTestWidth( this, id3 ) ) { + id = id3; + + } else { + id = id1; + } + } + +/* Return the result. */ + return astGetWidth( this, id ); + +} + +static int TestUseColour( AstPlot *this, int id, int *status ) { +/* +* Name: +* TestUseColour + +* Purpose: +* Test the Colour value for a specified graphical element. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int TestUseColour( AstPlot *this, int id, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This tests the Colour value for the graphical element specified by +* id. If an element related to a generic value is being accessed (e.g +* "Axes" is generic, "Axis1" and "Axis2" are not), then the element +* is considered to be set if all the corresponding specific values are +* set. + +* Parameters: +* this +* Pointer to the Plot. +* id +* An integer specifying the graphical element to be drawn. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Colour value state (1 if set, zero otherwise). + +*/ + +/* Local Variables: */ + int ret; + +/* Local Variables: */ + int id1; /* First genuine identifier */ + int id2; /* Second genuine identifier */ + int id3; /* Third genuine identifier */ + int nid; /* Number of genuine attributes */ + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* See if the supplied identifier is a psuedo-identifier representing two + or three other genuine identifiers. If so, return the logical AND of the + test flags for the genuine identifiers. */ + nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); + ret = astTestColour( this, id1 ); + if( nid > 1 ) ret = ret && astTestColour( this, id2 ); + if( nid > 2 ) ret = ret && astTestColour( this, id3 ); + +/* Return the result. */ + return ret; + +} + +static int TestUseFont( AstPlot *this, int id, int *status ) { +/* +* Name: +* TestUseFont + +* Purpose: +* Test the Font value for a specified graphical element. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int TestUseFont( AstPlot *this, int id, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This tests the Font value for the graphical element specified by +* id. If an element related to a generic value is being accessed (e.g +* "Axes" is generic, "Axis1" and "Axis2" are not), then the element +* is considered to be set if all the corresponding specific values are +* set. + +* Parameters: +* this +* Pointer to the Plot. +* id +* An integer specifying the graphical element to be drawn. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Font value state (1 if set, zero otherwise). + +*/ + +/* Local Variables: */ + int ret; + +/* Local Variables: */ + int id1; /* First genuine identifier */ + int id2; /* Second genuine identifier */ + int id3; /* Third genuine identifier */ + int nid; /* Number of genuine attributes */ + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* See if the supplied identifier is a psuedo-identifier representing two + or three other genuine identifiers. If so, return the logical AND of the + test flags for the genuine identifiers. */ + nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); + ret = astTestFont( this, id1 ); + if( nid > 1 ) ret = ret && astTestFont( this, id2 ); + if( nid > 2 ) ret = ret && astTestFont( this, id3 ); + +/* Return the result. */ + return ret; + +} + +static int TestUseSize( AstPlot *this, int id, int *status ) { +/* +* Name: +* TestUseSize + +* Purpose: +* Test the Size value for a specified graphical element. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int TestUseSize( AstPlot *this, int id, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This tests the Size value for the graphical element specified by +* id. If an element related to a generic value is being accessed (e.g +* "Axes" is generic, "Axis1" and "Axis2" are not), then the element +* is considered to be set if all the corresponding specific values are +* set. + +* Parameters: +* this +* Pointer to the Plot. +* id +* An integer specifying the graphical element to be drawn. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Size value state (1 if set, zero otherwise). + +*/ + +/* Local Variables: */ + int ret; + +/* Local Variables: */ + int id1; /* First genuine identifier */ + int id2; /* Second genuine identifier */ + int id3; /* Third genuine identifier */ + int nid; /* Number of genuine attributes */ + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* See if the supplied identifier is a psuedo-identifier representing two + or three other genuine identifiers. If so, return the logical AND of the + test flags for the genuine identifiers. */ + nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); + ret = astTestSize( this, id1 ); + if( nid > 1 ) ret = ret && astTestSize( this, id2 ); + if( nid > 2 ) ret = ret && astTestSize( this, id3 ); + +/* Return the result. */ + return ret; + +} + +static int TestUseStyle( AstPlot *this, int id, int *status ) { +/* +* Name: +* TestUseStyle + +* Purpose: +* Test the Style value for a specified graphical element. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int TestUseStyle( AstPlot *this, int id, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This tests the Style value for the graphical element specified by +* id. If an element related to a generic value is being accessed (e.g +* "Axes" is generic, "Axis1" and "Axis2" are not), then the element +* is considered to be set if all the corresponding specific values are +* set. + +* Parameters: +* this +* Pointer to the Plot. +* id +* An integer specifying the graphical element to be drawn. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Style value state (1 if set, zero otherwise). + +*/ + +/* Local Variables: */ + int ret; + +/* Local Variables: */ + int id1; /* First genuine identifier */ + int id2; /* Second genuine identifier */ + int id3; /* Third genuine identifier */ + int nid; /* Number of genuine attributes */ + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* See if the supplied identifier is a psuedo-identifier representing two + or three other genuine identifiers. If so, return the logical AND of the + test flags for the genuine identifiers. */ + nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); + ret = astTestStyle( this, id1 ); + if( nid > 1 ) ret = ret && astTestStyle( this, id2 ); + if( nid > 2 ) ret = ret && astTestStyle( this, id3 ); + +/* Return the result. */ + return ret; + +} + +static int TestUseWidth( AstPlot *this, int id, int *status ) { +/* +* Name: +* TestUseWidth + +* Purpose: +* Test the Width value for a specified graphical element. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int TestUseWidth( AstPlot *this, int id, int *status ) + +* Class Membership: +* Plot member function. + +* Description: +* This tests the Width value for the graphical element specified by +* id. If an element related to a generic value is being accessed (e.g +* "Axes" is generic, "Axis1" and "Axis2" are not), then the element +* is considered to be set if all the corresponding specific values are +* set. + +* Parameters: +* this +* Pointer to the Plot. +* id +* An integer specifying the graphical element to be drawn. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Width value state (1 if set, zero otherwise). + +*/ + +/* Local Variables: */ + int ret; + +/* Local Variables: */ + int id1; /* First genuine identifier */ + int id2; /* Second genuine identifier */ + int id3; /* Third genuine identifier */ + int nid; /* Number of genuine attributes */ + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* See if the supplied identifier is a psuedo-identifier representing two + or three other genuine identifiers. If so, return the logical AND of the + test flags for the genuine identifiers. */ + nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); + ret = astTestWidth( this, id1 ); + if( nid > 1 ) ret = ret && astTestWidth( this, id2 ); + if( nid > 2 ) ret = ret && astTestWidth( this, id3 ); + +/* Return the result. */ + return ret; + +} + +static int ToggleLogLin( AstPlot *this, int axis, int islog, + const char *method, int *status ){ +/* +* +* Name: +* ToggleLogLin + +* Purpose: +* Toggle the nature of the Plot axis mapping. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int ToggleLogLin( AstPlot *this, int axis, int islog, +* const char *method, int *status ) + +* Class Membership: +* Plot member function + +* Description: +* Each axis in the graphics Frame of a Plot can be mapped linearly or +* logarithmically onto the corresponding axis in the base Frame of +* the FrameSet supplied whtn the Plot was constructed. This function +* toggles the nature of the specified axis; if it is currently +* logarithmic it becomes linear, and if it is linear it becomes +* logarithmic. +* +* If the Frame canot be re-maped (for instance because the visible +* part of the axis includes the value zero), then zero is returned +* but no error is reported. + +* Parameters: +* this +* The Plot. +* axis +* Zero based axis index. +* islog +* Is the axis currently logarithmic? If so, this function remaps +* it so that it is linear (and vice-versa). +* method +* Pointer to a null-terminated string holding the name of the calling +* method (only used within error mesages). +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Non-zero if the attempt to re-map the graphics Frame was succesful, +* zero otherwise. + +*/ + +/* Local Variables: */ + AstCmpMap *remap1; /* 1D Mapping to re-map the graphics Frame */ + AstCmpMap *remap2; /* 2D Mapping to re-map the graphics Frame */ + AstMathMap *logmap; /* 1D Logarithmic axis Mapping */ + AstUnitMap *unitmap; /* 1D Unit mapping */ + AstWinMap *linmap; /* 1D Linear axis Mapping */ + char fwdexp[ 25 + 2*DBL_DIG ]; /* Forward log mapping expression */ + char invexp[ 28 + 2*DBL_DIG ]; /* Inverse log mapping expression */ + const char *fwd[1]; /* Pointer to pass to MathMap constructor */ + const char *inv[1]; /* Pointer to pass to MathMap constructor */ + double a; /* Constant for log expression */ + double b1; /* Original base Frame axis value at first edge */ + double b2; /* Original base Frame axis value at second edge */ + double b; /* Constant for log expression */ + double c; /* Constant for log expression */ + double g1; /* Graphics axis value at first edge */ + double g2; /* Graphics axis value at second edge */ + int result; /* Returned value */ + +/* Inotialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Get the corresponding axis limits in the graphics coordinate system + and the original base Frame coordinate system. */ + if( axis == 0 ) { + if( this->xrev ) { + g1 = this->xhi; + g2 = this->xlo; + } else { + g1 = this->xlo; + g2 = this->xhi; + } + b1 = this->bbox[ 0 ]; + b2 = this->bbox[ 2 ]; + + } else { + if( this->yrev ) { + g1 = this->yhi; + g2 = this->ylo; + } else { + g1 = this->ylo; + g2 = this->yhi; + } + b1 = this->bbox[ 1 ]; + b2 = this->bbox[ 3 ]; + } + +/* Check the limits are usable (e.g. the base Frame values will be bad + if this Plot was restored from a dump of a Plot created before the + LogPlot attributes were added). */ + if( b1 != AST__BAD && b2 != AST__BAD && g1 != g2 && b1 != b2 && + b1*b2 > 0.0 ) { + +/* Form the 1D Mapping which maps the specified axis linearly onto the plotting + surface. The forward transformation goes from graphics to base Frame. */ + linmap = astWinMap( 1, &g1, &g2, &b1, &b2, "", status ); + +/* Form the 1D Mapping which maps the specified axis logarithmically onto the + plotting surface. The forward transformation goes from graphics to base + Frame. */ + c = log10( b1/b2 ); + a = ( g1 - g2 )/c; + + if( b1 > 0.0 ) { + b = ( g2*log10( b1 ) - g1*log10( b2 ) )/c; + (void) sprintf( invexp, "g=%.*g*log10(b)+%.*g", DBL_DIG, a, DBL_DIG, b ); + (void) sprintf( fwdexp, "b=pow(10,(g-%.*g)/%.*g)", DBL_DIG, b, DBL_DIG, a ); + + } else { + b = ( g2*log10( -b1 ) - g1*log10( -b2 ) )/c; + (void) sprintf( invexp, "g=%.*g*log10(-b)+%.*g", DBL_DIG, a, DBL_DIG, b ); + (void) sprintf( fwdexp, "b=-pow(10,(g-%.*g)/%.*g)", DBL_DIG, b, DBL_DIG, a ); + } + + fwd[ 0 ] = (const char *) fwdexp; + inv[ 0 ] = (const char *) invexp; + logmap = astMathMap( 1, 1, 1, fwd, 1, inv, "SimpFI=1,SimpIF=1", status ); + +/* If the axis was previously logarithmic, get the Mapping with which to remap + the graphics Frame so that it becomes linearly related to the base Frame + in the FrameSet supplied when the Plot was constructed. */ + if( islog ) { + astInvert( linmap ); + remap1 = astCmpMap( logmap, linmap, 1, "", status ); + +/* If the axis was previously linear, store the new value and get the Mapping + with which to remap the graphics Frame so that it becomes logarithmically + related to the base Frame in the FrameSet supplied when the Plot was + constructed. */ + } else { + astInvert( logmap ); + remap1 = astCmpMap( linmap, logmap, 1, "", status ); + } + +/* Add a 1D UnitMap to map the unaltered mapping. */ + unitmap = astUnitMap( 1, "", status ); + if( axis == 0 ) { + remap2 = astCmpMap( remap1, unitmap, 0, "", status ); + } else { + remap2 = astCmpMap( unitmap, remap1, 0, "", status ); + } + +/* Remap the base (graphics) Frame in the Plot. */ + astRemapFrame( this, AST__BASE, remap2 ); + +/* Free resources. */ + remap1 = astAnnul( remap1 ); + remap2 = astAnnul( remap2 ); + logmap = astAnnul( logmap ); + linmap = astAnnul( linmap ); + unitmap = astAnnul( unitmap ); + +/* Indicate success. */ + if( astOK ) result = 1; + + } + +/* Return the result. */ + return result; +} + +static int Ustrcmp( const char *a, const char *b, int *status ){ +/* +* Name: +* Ustrncmp + +* Purpose: +* A case blind version of strcmp. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int Ustrcmp( const char *a, const char *b ) + +* Class Membership: +* Plot member function. + +* Description: +* Returns 0 if there are no differences between the two strings, and 1 +* otherwise. Comparisons are case blind. + +* Parameters: +* a +* Pointer to first string. +* b +* Pointer to second string. + +* Returned Value: +* Zero if the strings match, otherwise one. + +* Notes: +* - This function does not consider the sign of the difference between +* the two strings, whereas "strcmp" does. +* - This function attempts to execute even if an error has occurred. + +*/ + +/* Local Variables: */ + const char *aa; /* Pointer to next "a" character */ + const char *bb; /* Pointer to next "b" character */ + int ret; /* Returned value */ + +/* Initialise the returned value to indicate that the strings match. */ + ret = 0; + +/* Initialise pointers to the start of each string. */ + aa = a; + bb = b; + +/* Loop round each character. */ + while( 1 ){ + +/* We leave the loop if either of the strings has been exhausted. */ + if( !(*aa ) || !(*bb) ){ + +/* If one of the strings has not been exhausted, indicate that the + strings are different. */ + if( *aa || *bb ) ret = 1; + +/* Break out of the loop. */ + break; + +/* If neither string has been exhausted, convert the next characters to + upper case and compare them, incrementing the pointers to the next + characters at the same time. If they are different, break out of the + loop. */ + } else { + + if( toupper( (int) *(aa++) ) != toupper( (int) *(bb++) ) ){ + ret = 1; + break; + } + + } + + } + +/* Return the result. */ + return ret; + +} + +static int Ustrncmp( const char *a, const char *b, size_t n, int *status ){ +/* +* Name: +* Ustrncmp + +* Purpose: +* A case blind version of strncmp. + +* Type: +* Private function. + +* Synopsis: +* #include "plot.h" +* int Ustrncmp( const char *a, const char *b, size_t n ) + +* Class Membership: +* Plot member function. + +* Description: +* Returns 0 if there are no differences between the first "n" +* characters of the two strings, and 1 otherwise. Comparisons are +* case blind. + +* Parameters: +* a +* Pointer to first string. +* b +* Pointer to second string. +* n +* The maximum number of characters to compare. + +* Returned Value: +* Zero if the strings match, otherwise one. + +* Notes: +* - This function does not consider the sign of the difference +* between the two strings, whereas "strncmp" does. +* - This function attempts to execute even if an error has +* occurred. + +*/ + +/* Local Variables: */ + const char *aa; /* Pointer to next "a" character */ + const char *bb; /* Pointer to next "b" character */ + int i; /* Character index */ + int ret; /* Returned value */ + +/* Initialise the returned value to indicate that the strings match. */ + ret = 0; + +/* Initialise pointers to the start of each string. */ + aa = a; + bb = b; + +/* Compare up to "n" characters. */ + for( i = 0; i < (int) n; i++ ){ + +/* We leave the loop if either of the strings has been exhausted. */ + if( !(*aa ) || !(*bb) ){ + +/* If one of the strings has not been exhausted, indicate that the + strings are different. */ + if( *aa || *bb ) ret = 1; + +/* Break out of the loop. */ + break; + +/* If neither string has been exhausted, convert the next characters to + upper case and compare them, incrementing the pointers to the next + characters at the same time. If they are different, break out of the + loop. */ + } else { + + if( toupper( (int) *(aa++) ) != toupper( (int) *(bb++) ) ){ + ret = 1; + break; + } + + } + + } + +/* Return the result. */ + return ret; + +} + +/* Destructor. */ +/* ----------- */ +static void Delete( AstObject *obj, int *status ) { +/* +* Name: +* Delete + +* Purpose: +* Destructor for Plot objects. + +* Type: +* Private function. + +* Synopsis: +* void Delete( AstObject *obj, int *status ) + +* Description: +* This function implements the destructor for Plot objects. + +* Parameters: +* obj +* Pointer to the object to be deleted. +* status +* Pointer to the inherited status variable. + +* Notes: +* This function attempts to execute even if the global error status is +* set. +*/ + +/* Local Variables: */ + AstPlot *this; /* Pointer to Plot */ + int i; + +/* Obtain a pointer to the Plot structure. */ + this = (AstPlot *) obj; + +/* Free the clipping bounds arrays. */ + this->clip_lbnd = (double *) astFree( (void *) this->clip_lbnd ); + this->clip_ubnd = (double *) astFree( (void *) this->clip_ubnd ); + +/* Free the Grf function stack */ + this->grfstack = (AstGrfPtrs *) astFree( (void *) this->grfstack ); + +/* Free the graphics attribute stack. */ + for( i = this->ngat - 1; i >= 0; i-- ) { + this->gat[ i ] = astFree( this->gat[ i ] ); + } + +/* Free the graphics context pointer. */ + if( this->grfcontext ) { + this->grfcontext = astAnnul( this->grfcontext ); + this->grfcontextID = astAnnulId( this->grfcontextID ); + } + +/* Free the information about the tick marks to draw. */ + for( i = 0; i < 3; i++ ) { + this->majtickval[ i ] = astFree( this->majtickval[ i ] ); + this->mintickval[ i ] = astFree( this->mintickval[ i ] ); + this->nmajtickval[ i ] = 0; + this->nmintickval[ i ] = 0; + } + +/* Free the information about the drawn tick marks. */ + SaveTick( this, -1, 0.0, 0.0, 0, status ); +} + +/* Copy constructor. */ +/* ----------------- */ +static void Copy( const AstObject *objin, AstObject *objout, int *status ) { +/* +* Name: +* Copy + +* Purpose: +* Copy constructor for Plot objects. + +* Type: +* Private function. + +* Synopsis: +* void Copy( const AstObject *objin, AstObject *objout, int *status ) + +* Description: +* This function implements the copy constructor for Plot objects. + +* Parameters: +* objin +* Pointer to the object to be copied. +* objout +* Pointer to the object being constructed. +* status +* Pointer to the inherited status variable. + +* Notes: +* - This constructor makes a deep copy. +*/ + +/* Local Variables: */ + AstPlot *in; /* Pointer to input Plot */ + AstPlot *out; /* Pointer to output Plot */ + int axis; /* Zero based axis index */ + int n; /* Number of ticks saved */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain pointers to the input and output Plots. */ + in = (AstPlot *) objin; + out = (AstPlot *) objout; + +/* For safety, first clear any references to the input memory from + the output Plot. */ + out->clip_lbnd = NULL; + out->clip_ubnd = NULL; + out->gat = NULL; + out->ngat = 0; + + for( axis = 0; axis < 3; axis++ ) { + out->majtickgx[ axis ] = NULL; + out->majtickgy[ axis ] = NULL; + out->majtickcount[ axis ] = 0; + out->mintickgx[ axis ] = NULL; + out->mintickgy[ axis ] = NULL; + out->mintickcount[ axis ] = 0; + out->majtickval[ axis ] = NULL; + out->nmajtickval[ axis ] = 0; + out->mintickval[ axis ] = NULL; + out->nmintickval[ axis ] = 0; + } + +/* Copy the clipping bounds arrays. */ + out->clip_lbnd = (double *) astStore( NULL, (void *) in->clip_lbnd, + sizeof(double)*(size_t)(in->clip_axes) ); + out->clip_ubnd = (double *) astStore( NULL, (void *) in->clip_ubnd, + sizeof(double)*(size_t)(in->clip_axes) ); + +/* Copy the Grf function stack */ + out->grfstack = (AstGrfPtrs *) astStore( NULL, (void *) in->grfstack, + sizeof(AstGrfPtrs)*(size_t)(in->grfnstack )); + +/* Copy the information about drawn tick marks. */ + for( axis = 0; axis < 3; axis++ ) { + n = in->majtickcount[ axis ]; + out->majtickgx[ axis ] = (double *) astStore( NULL, in->majtickgx[ axis ], + n*sizeof( double ) ); + out->majtickgy[ axis ] = (double *) astStore( NULL, in->majtickgy[ axis ], + n*sizeof( double ) ); + out->majtickcount[ axis ] = n; + + n = in->mintickcount[ axis ]; + out->mintickgx[ axis ] = (double *) astStore( NULL, in->mintickgx[ axis ], + n*sizeof( double ) ); + out->mintickgy[ axis ] = (double *) astStore( NULL, in->mintickgy[ axis ], + n*sizeof( double ) ); + out->mintickcount[ axis ] = n; + + n = in->nmajtickval[ axis ]; + out->majtickval[ axis ] = (double *) astStore( NULL, in->majtickval[ axis ], + n*sizeof( double ) ); + out->nmajtickval[ axis ] = n; + + n = in->nmintickval[ axis ]; + out->mintickval[ axis ] = (double *) astStore( NULL, in->mintickval[ axis ], + n*sizeof( double ) ); + out->nmintickval[ axis ] = n; + } + +/* If an error occurred, free any allocated memory. */ + if ( !astOK ) { + out->clip_lbnd = (double *) astFree( out->clip_lbnd ); + out->clip_ubnd = (double *) astFree( out->clip_ubnd ); + out->grfstack = (AstGrfPtrs *) astFree( out->grfstack ); + SaveTick( out, -1, 0.0, 0.0, 0, status ); + } +} + +/* Dump function. */ +/* -------------- */ +static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { +/* +* Name: +* Dump + +* Purpose: +* Dump function for Plot objects. + +* Type: +* Private function. + +* Synopsis: +* void Dump( AstObject *this, AstChannel *channel, int *status ) + +* Description: +* This function implements the Dump function which writes out data +* for the Plot class to an output Channel. + +* Parameters: +* this +* Pointer to the Plot whose data are being written. +* channel +* Pointer to the Channel to which the data are being written. +* status +* Pointer to the inherited status variable. +*/ + +#define KEY_LEN 50 /* Maximum length of a keyword */ + +/* Local Variables: */ + AstPlot *this; /* Pointer to the Plot structure */ + char buff[ KEY_LEN + 1 ]; /* Buffer for keyword string */ + char *comment; /* Pointer to comment string */ + double dval; /* Double precision value */ + int ax; /* Axis to which element refers */ + int axis; /* Zero based axis index */ + int id; /* Zero based graphical object id */ + int ival; /* Integer value */ + int itick; /* Tick mark index */ + int nax; /* Number of base Frame axes */ + int set; /* Attribute value set? */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the Plot structure. */ + this = (AstPlot *) this_object; + +/* Get the number of graphics (base) frame axes - 2 for a Plot, 3 for a + Plot3D. */ + nax = astGetNin( this ); + +/* Write out values representing the instance variables for the + Plot class. Accompany these with appropriate comment strings, + possibly depending on the values being written.*/ + +/* In the case of attributes, we first use the appropriate (private) + Test... member function to see if they are set. If so, we then use + the (private) Get... function to obtain the value to be written + out. + + For attributes which are not set, we use the astGet... method to + obtain the value instead. This will supply a default value + (possibly provided by a derived class which over-rides this method) + which is more useful to a human reader as it corresponds to the + actual default attribute value. Since "set" will be zero, these + values are for information only and will not be read back. */ + +/* Tol. */ +/* ---- */ + set = TestTol( this, status ); + dval = set ? GetTol( this, status ) : astGetTol( this ); + astWriteDouble( channel, "Tol", set, 0, dval, "Plotting tolerance" ); + +/* Grid. */ +/* ----- */ + set = TestGrid( this, status ); + ival = set ? GetGrid( this, status ) : astGetGrid( this ); + astWriteInt( channel, "Grid", set, 0, ival, "Is a grid required?" ); + +/* TickAll. */ +/* -------- */ + set = TestTickAll( this, status ); + ival = set ? GetTickAll( this, status ) : astGetTickAll( this ); + astWriteInt( channel, "TckAll", set, 1, ival, "Put ticks on all edges?" ); + +/* ForceExterior. */ +/* -------------- */ + set = TestForceExterior( this, status ); + ival = set ? GetForceExterior( this, status ) : astGetForceExterior( this ); + astWriteInt( channel, "FrcExt", set, 1, ival, "Force exterior labelling?" ); + +/* Invisible. */ +/* ---------- */ + set = TestInvisible( this, status ); + ival = set ? GetInvisible( this, status ) : astGetInvisible( this ); + astWriteInt( channel, "Invsbl", set, 1, ival, "Use invisible ink?" ); + +/* Border. */ +/* ------- */ + set = TestBorder( this, status ); + ival = set ? GetBorder( this, status ) : astGetBorder( this ); + astWriteInt( channel, "Border", set, 0, ival, "Draw a border round the grid?" ); + +/* ClipOp. */ +/* ------- */ + set = TestClipOp( this, status ); + ival = set ? GetClipOp( this, status ) : astGetClipOp( this ); + astWriteInt( channel, "ClpOp", set, 0, ival, "Clip using logical OR?" ); + +/* Clip. */ +/* ----- */ + set = TestClip( this, status ); + ival = set ? GetClip( this, status ) : astGetClip( this ); + astWriteInt( channel, "Clip", set, 0, ival, + ((ival == 0)?"Do not clip at plot edges": + ((ival == 1)?"Clip curves at plot edges": + ((ival == 2)?"Clip markers at plot edges": + "Clip markers and curves at plot edges")))); + +/* DrawTitle. */ +/* --------- */ + set = TestDrawTitle( this, status ); + ival = set ? GetDrawTitle( this, status ) : astGetDrawTitle( this ); + astWriteInt( channel, "DrwTtl", set, 1, ival, "Add a title to the grid?" ); + +/* DrawAxesUnits(axis). */ +/* ----------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestDrawAxes( this, axis, status ); + ival = set ? GetDrawAxes( this, axis, status ) : astGetDrawAxes( this, axis ); + (void) sprintf( buff, "DrwAxs%d", axis + 1 ); + astWriteInt( channel, buff, set, 0, ival, "Draw axis through ticks?" ); + } + +/* Abbrev(axis). */ +/* ------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestAbbrev( this, axis, status ); + ival = set ? GetAbbrev( this, axis, status ) : astGetAbbrev( this, axis ); + (void) sprintf( buff, "Abbrv%d", axis + 1 ); + astWriteInt( channel, buff, set, 0, ival, "Abbreviate numerical axis labels?" ); + } + +/* Escape. */ +/* ------- */ + set = TestEscape( this, status ); + ival = set ? GetEscape( this, status ) : astGetEscape( this ); + astWriteInt( channel, "Escape", set, 1, ival, "Interpret escape sequences?" ); + +/* LabelAt(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestLabelAt( this, axis, status ); + dval = set ? GetLabelAt( this, axis, status ) : astGetLabelAt( this, axis ); + if( dval != AST__BAD ){ + (void) sprintf( buff, "LblAt%d", axis + 1 ); + astWriteDouble( channel, buff, set, 0, dval, "Put numerical labels at" ); + } + } + +/* Centre(axis). */ +/* ------------ */ + for( axis = 0; axis < nax; axis++ ){ + set = TestCentre( this, axis, status ); + dval = set ? GetCentre( this, axis, status ) : astGetCentre( this, axis ); + if( dval != AST__BAD ){ + (void) sprintf( buff, "Cen%d", axis + 1 ); + astWriteDouble( channel, buff, set, 0, dval, "Tick mark origin" ); + } + } + +/* Gap(axis). */ +/* ---------- */ +/* Discovering the default value requires a lot of calculation. Only + write out this attribute if an explicit value has been set. */ + for( axis = 0; axis < nax; axis++ ){ + if( astTestGap( this, axis ) ) { + dval = astGetGap( this, axis ); + if( dval != AST__BAD ){ + (void) sprintf( buff, "Gap%d", axis + 1 ); + astWriteDouble( channel, buff, set, 0, dval, "Difference between ticks" ); + } + } + } + +/* LogGap(axis). */ +/* ------------- */ +/* Discovering the default value requires a lot of calculation. Only + write out this attribute if an explicit value has been set. */ + for( axis = 0; axis < nax; axis++ ){ + if( astTestLogGap( this, axis ) ) { + dval = astGetLogGap( this, axis ); + if( dval != AST__BAD ){ + (void) sprintf( buff, "LgGap%d", axis + 1 ); + astWriteDouble( channel, buff, set, 0, dval, "Ratio between ticks" ); + } + } + } + +/* NumLabGap(axis). */ +/* ---------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestNumLabGap( this, axis, status ); + dval = set ? GetNumLabGap( this, axis, status ) : astGetNumLabGap( this, axis ); + if( dval != AST__BAD ) { + (void) sprintf( buff, "NmGap%d", axis + 1 ); + astWriteDouble( channel, buff, set, 1, dval, "Spacing of numerical labels" ); + } + } + +/* TextLabGap(axis). */ +/* ----------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestTextLabGap( this, axis, status ); + dval = set ? GetTextLabGap( this, axis, status ) : astGetTextLabGap( this, axis ); + if( dval != AST__BAD ) { + (void) sprintf( buff, "TxGap%d", axis + 1 ); + astWriteDouble( channel, buff, set, 1, dval, "Spacing of descriptive labels" ); + } + } + +/* LabelUp(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestLabelUp( this, axis, status ); + ival = set ? GetLabelUp( this, axis, status ) : astGetLabelUp( this, axis ); + (void) sprintf( buff, "LblUp%d", axis + 1 ); + astWriteInt( channel, buff, set, 1, ival, "Draw numerical labels upright?" ); + } + +/* LogPlot(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestLogPlot( this, axis, status ); + ival = set ? GetLogPlot( this, axis, status ) : astGetLogPlot( this, axis ); + (void) sprintf( buff, "LgPlt%d", axis + 1 ); + astWriteInt( channel, buff, set, 1, ival, "Map plot axis logarithmically?" ); + } + +/* LogTicks(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestLogTicks( this, axis, status ); + ival = set ? GetLogTicks( this, axis, status ) : astGetLogTicks( this, axis ); + (void) sprintf( buff, "LgTck%d", axis + 1 ); + astWriteInt( channel, buff, set, 1, ival, "Space ticks logarithmically?" ); + } + +/* LogLabel(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestLogLabel( this, axis, status ); + ival = set ? GetLogLabel( this, axis, status ) : astGetLogLabel( this, axis ); + (void) sprintf( buff, "LgLbl%d", axis + 1 ); + astWriteInt( channel, buff, set, 1, ival, "Scientific notation for labels?" ); + } + +/* NumLab(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestNumLab( this, axis, status ); + ival = set ? GetNumLab( this, axis, status ) : astGetNumLab( this, axis ); + (void) sprintf( buff, "NmLbl%d", axis + 1 ); + astWriteInt( channel, buff, set, 1, ival, "Draw numerical labels?" ); + } + +/* MinTick(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestMinTick( this, axis, status ); + ival = set ? GetMinTick( this, axis, status ) : astGetMinTick( this, axis ); + (void) sprintf( buff, "MnTks%d", axis + 1 ); + astWriteInt( channel, buff, set, 0, ival, "No. of sub-divisions " + "between major tick marks" ); + } + +/* TextLab(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestTextLab( this, axis, status ); + ival = set ? GetTextLab( this, axis, status ) : astGetTextLab( this, axis ); + (void) sprintf( buff, "TxLbl%d", axis + 1 ); + astWriteInt( channel, buff, set, 0, ival, "Draw textual label?" ); + } + +/* LabelUnits(axis). */ +/* ----------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestLabelUnits( this, axis, status ); + ival = set ? GetLabelUnits( this, axis, status ) : astGetLabelUnits( this, axis ); + (void) sprintf( buff, "LbUnt%d", axis + 1 ); + astWriteInt( channel, buff, set, 0, ival, "Add units to axis label?" ); + } + +/* Style(object). */ +/* -------------- */ + for( id = 0; id < AST__NPID; id++ ){ + set = TestStyle( this, id, status ); + ival = set ? GetStyle( this, id, status ) : astGetStyle( this, id ); + (void) sprintf( buff, "Style%d", id + 1 ); + comment = GrfItem( id, " line style", &ax, status ); + if( ax < nax ) astWriteInt( channel, buff, set, 0, ival, comment ); + comment = (char *) astFree( (void *) comment ); + } + +/* Font(object). */ +/* ------------- */ + for( id = 0; id < AST__NPID; id++ ){ + set = TestFont( this, id, status ); + ival = set ? GetFont( this, id, status ) : astGetFont( this, id ); + (void) sprintf( buff, "Font%d", id + 1 ); + comment = GrfItem( id, " character font", &ax, status ); + if( ax < nax ) astWriteInt( channel, buff, set, 0, ival, comment ); + comment = (char *) astFree( (void *) comment ); + } + +/* Colour(object). */ +/* --------------- */ + for( id = 0; id < AST__NPID; id++ ){ + set = TestColour( this, id, status ); + ival = set ? GetColour( this, id, status ) : astGetColour( this, id ); + (void) sprintf( buff, "Col%d", id + 1 ); + comment = GrfItem( id, " colour index", &ax, status ); + if( ax < nax ) astWriteInt( channel, buff, set, 0, ival, comment ); + comment = (char *) astFree( (void *) comment ); + } + +/* Width(object). */ +/* -------------- */ + for( id = 0; id < AST__NPID; id++ ){ + set = TestWidth( this, id, status ); + dval = set ? GetWidth( this, id, status ) : astGetWidth( this, id ); + if( dval != AST__BAD ) { + (void) sprintf( buff, "Width%d", id + 1 ); + comment = GrfItem( id, " line width", &ax, status ); + if( ax < nax ) astWriteDouble( channel, buff, set, 0, dval, comment ); + comment = (char *) astFree( (void *) comment ); + } + } + +/* Size(object). */ +/* ------------- */ + for( id = 0; id < AST__NPID; id++ ){ + set = TestSize( this, id, status ); + dval = set ? GetSize( this, id, status ) : astGetSize( this, id ); + if( dval != AST__BAD ) { + (void) sprintf( buff, "Size%d", id + 1 ); + comment = GrfItem( id, " character size", &ax, status ); + if( ax < nax ) astWriteDouble( channel, buff, set, 0, dval, comment ); + comment = (char *) astFree( (void *) comment ); + } + } + +/* TitleGap. */ +/* --------- */ + set = TestTitleGap( this, status ); + dval = set ? GetTitleGap( this, status ) : astGetTitleGap( this ); + if( dval != AST__BAD ) astWriteDouble( channel, "TtlGap", set, 1, dval, + "Gap between title and edge" ); + +/* MajTickLen(axis). */ +/* ----------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestMajTickLen( this, axis, status ); + dval = set ? GetMajTickLen( this, axis, status ) : astGetMajTickLen( this, axis ); + if( dval != AST__BAD ) { + (void) sprintf( buff, "MjTkLn%d", axis + 1 ); + astWriteDouble( channel, buff, set, 0, dval, "Major tick length" ); + } + } + +/* MinTickLen(axis). */ +/* ----------------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestMinTickLen( this, axis, status ); + dval = set ? GetMinTickLen( this, axis, status ) : astGetMinTickLen( this, axis ); + if( dval != AST__BAD ) { + (void) sprintf( buff, "MnTkLn%d", axis + 1 ); + astWriteDouble( channel, buff, set, 1, dval, "Minor tick length" ); + } + } + +/* Labelling. */ +/* ---------- */ + set = TestLabelling( this, status ); + ival = set ? GetLabelling( this, status ) : astGetLabelling( this ); + comment = "Labelling scheme"; + astWriteString( channel, "Lbling", set, 0, xlbling[ival], comment ); + +/* Edge(axis). */ +/* ----------- */ + for( axis = 0; axis < nax; axis++ ){ + set = TestEdge( this, axis, status ); + ival = set ? GetEdge( this, axis, status ) : astGetEdge( this, axis ); + (void) sprintf( buff, "Edge%d", axis + 1 ); + comment = "Edge used to label an axis"; + astWriteString( channel, buff, set, 0, xedge[ival], comment ); + } + +/* Now do instance variables which are not attributes. */ +/* =================================================== */ + +/* Only write out clipping information if set. */ + if( this->clip_lbnd && this->clip_ubnd ){ + +/* The lower bounds of the clipping volume. */ + for( axis = 0; axis < this->clip_axes; axis++ ){ + (void) sprintf( buff, "ClpLb%d", axis + 1 ); + if( this->clip_lbnd && (this->clip_lbnd)[ axis ] != AST__BAD ){ + astWriteDouble( channel, buff, 1, 0, (this->clip_lbnd)[ axis ], + "Lower bound of clipping region" ); + } + } + +/* The upper bounds of the clipping volume. */ + for( axis = 0; axis < this->clip_axes; axis++ ){ + (void) sprintf( buff, "ClpUb%d", axis + 1 ); + if( this->clip_ubnd && (this->clip_ubnd)[ axis ] != AST__BAD ){ + astWriteDouble( channel, buff, 1, 0, (this->clip_ubnd)[ axis ], + "Upper bound of clipping region" ); + } + } + +/* The number of bounds supplied for the clipping volume. */ + astWriteInt( channel, "ClpAxs", 1, 0, this->clip_axes, + "No. of bounds for clipping region" ); + +/* The index of the clipping Frame within the Plot. */ + astWriteInt( channel, "ClpFrm", 1, 0, this->clip_frame, + "Index of clipping Frame" ); + } + +/* The bounds of the plotting area in graphics coords. */ + astWriteDouble( channel, "Xlo", 1, 1, this->xlo, + "Lower X bound of plotting area" ); + astWriteDouble( channel, "Ylo", 1, 1, this->ylo, + "Lower Y bound of plotting area" ); + astWriteDouble( channel, "Xhi", 1, 1, this->xhi, + "Upper X bound of plotting area" ); + astWriteDouble( channel, "Yhi", 1, 1, this->yhi, + "Upper Y bound of plotting area" ); + +/* Axis reversal flags. */ + astWriteInt( channel, "Xrev", 1, 0, this->xrev, "X axis reversed?" ); + astWriteInt( channel, "Yrev", 1, 0, this->yrev, "Y axis reversed?" ); + +/* The bounds of the plotting area in the base Frame of the FrameSet + supplied when the Plot was constructed. */ + astWriteDouble( channel, "Xb1", 1, 1, this->bbox[ 0 ], + "Lower X bound of supplied base Frame" ); + astWriteDouble( channel, "Yb1", 1, 1, this->bbox[ 1 ], + "Lower Y bound of supplied base Frame" ); + astWriteDouble( channel, "Xb2", 1, 1, this->bbox[ 2 ], + "Upper X bound of supplied base Frame" ); + astWriteDouble( channel, "Yb2", 1, 1, this->bbox[ 3 ], + "Upper Y bound of supplied base Frame" ); + +/* User-specified tick values */ + for( axis = 0; axis < 3; axis++ ) { + + if( this->nmajtickval[ axis ] > 0 ) { + sprintf( buff, "NMjTk%d", axis + 1 ); + astWriteInt( channel, buff, 1, 1, this->nmajtickval[ axis ], "" ); + + for( itick = 0; itick < this->nmajtickval[ axis ]; itick++ ) { + sprintf( buff, "MjTk%d_%d", axis + 1, itick + 1 ); + astWriteDouble( channel, buff, 1, 1, + this->majtickval[ axis ][ itick ], "" ); + } + } + + if( this->nmintickval[ axis ] > 0 ) { + sprintf( buff, "NMnTk%d", axis + 1 ); + astWriteInt( channel, buff, 1, 1, this->nmintickval[ axis ], "" ); + + for( itick = 0; itick < this->nmintickval[ axis ]; itick++ ) { + sprintf( buff, "MnTk%d_%d", axis + 1, itick + 1 ); + astWriteDouble( channel, buff, 1, 1, + this->mintickval[ axis ][ itick ], "" ); + } + } + } + +/* Return. */ + return; + +/* Undefine macros local to this function. */ +#undef KEY_LEN +} + + +/* Standard class functions. */ +/* ========================= */ +/* Implement the astIsAPlot and astCheckPlot functions using + the macros defined for this purpose in the "object.h" header + file. */ +astMAKE_ISA(Plot,FrameSet) +astMAKE_CHECK(Plot) + +AstPlot *astPlot_( void *frame_void, const float *graphbox, + const double *basebox, const char *options, int *status, ...) { +/* +*+ +* Name: +* astPlot + +* Purpose: +* Create a Plot. + +* Type: +* Protected function. + +* Synopsis: +* #include "plot.h" +* AstPlot *astPlot( AstFrame *frame, const float *graphbox, +* const double *basebox, const char *options, ..., int *status ) + +* Class Membership: +* Plot constructor. + +* Description: +* This function creates a new Plot and optionally initialises +* its attributes. +* +* The supplied Frame (or the base frame if a FrameSet was supplied) is +* assumed to be related to the graphics world coordinate system by a +* simple shift and scale along each axis. The mapping between graphics +* world coordinates and this Frame is specified by supplying the +* coordinates in both systems at the bottom left and top right corners +* of a box on the graphics device. By default, no graphics will be +* produced outside the supplied box, but this default behaviour can be +* changed by setting explicit values for the various clipping attributes. + +* Parameters: +* frame +* A pointer to a Frame or FrameSet to be annotated. If a NULL pointer +* is supplied, then a default 2-D Frame will be created to which labels, +* etc, can be attached by setting the relevant Frame attributes. +* graphbox +* A pointer to an array of 4 values giving the graphics world +* coordinates of the bottom left and top right corners of a box on +* the graphics output device. The first pair of values should be the +* coordinates of the bottom left corner of the box and the second +* pair of values should be the coordinates of the top right corner. +* The horizontal axis should be given first in each pair. +* basebox +* A pointer to an array of 4 values giving the coordinates in the +* supplied Frame, or base frame of the supplied FrameSet, at the +* bottom left and top right corners of the box specified by parameter +* graphbox. These should be supplied in the same order as for +* parameter "graphbox". +* options +* Pointer to a null terminated string containing an optional +* comma-separated list of attribute assignments to be used for +* initialising the new Plot. The syntax used is the same as +* for the astSet method and may include "printf" format +* specifiers identified by "%" symbols in the normal way. +* status +* Pointer to the inherited status variable. +* ... +* If the "options" string contains "%" format specifiers, then +* an optional list of arguments may follow it in order to +* supply values to be substituted for these specifiers. The +* rules for supplying these are identical to those for the +* astSet method (and for the C "printf" function). + +* Returned Value: +* A pointer to the new Plot. + +* Notes: +* - The base Frame of the created Plot corresponds to the graphics world +* coordinate system, and should not, in general, be changed. +* - The current Frame of the created Plot corresponds to the Frame +* given by parameter "frame". If a FrameSet was supplied then its +* current Frame becomes the current Frame of the created Plot. +* - If the supplied Frame, or base Frame if a FrameSet was supplied, +* has more than 2 axes, then the sub-Frame defined by the first 2 axes +* is used. +* - A NULL pointer will be returned if this function is invoked with the +* global error status set, or if it should fail for any reason. +*- + +* Implementation Notes: +* - This function implements the basic Plot constructor which +* is available via the protected interface to the Plot class. +* A public interface is provided by the astPlotId_ function. +* - Because this function has a variable argument list, it is +* invoked by a macro that evaluates to a function pointer (not a +* function invocation) and no checking or casting of arguments is +* performed before the function is invoked. Because of this, the +* "frame" parameter is of type (void *) and is converted and +* validated within the function itself. + +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstFrame *frame; /* Pointer to Frame structure */ + AstPlot *new; /* Pointer to new Plot */ + va_list args; /* Variable argument list */ + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Check the global status. */ + if ( !astOK ) return NULL; + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + new = NULL; + +/* Obtain and validate a pointer to any supplied Frame structure. */ + if( frame_void ){ + frame = astCheckFrame( frame_void ); + } else { + frame = NULL; + } + +/* Check the pointer can be used. */ + if ( astOK ) { + +/* Initialise the Plot, allocating memory and initialising the + virtual function table as well if necessary. */ + new = astInitPlot( NULL, sizeof( AstPlot ), !class_init, + &class_vtab, "Plot", frame, graphbox, + basebox ); + +/* If successful, note that the virtual function table has been + initialised. */ + if ( astOK ) { + class_init = 1; + +/* Obtain the variable argument list and pass it along with the + options string to the astVSet method to initialise the new + Plot's attributes. */ + va_start( args, status ); + astVSet( new, options, NULL, args ); + va_end( args ); + +/* If an error occurred, clean up by deleting the new object. */ + if ( !astOK ) new = astDelete( new ); + } + } + +/* Return a pointer to the new Plot. */ + return new; +} + +AstPlot *astInitPlot_( void *mem, size_t size, int init, AstPlotVtab *vtab, + const char *name, AstFrame *frame, const float *graphbox, + const double *basebox, int *status ) { +/* +*+ +* Name: +* astInitPlot + +* Purpose: +* Initialise a Plot. + +* Type: +* Protected function. + +* Synopsis: +* #include "plot.h" +* AstPlot *astInitPlot( void *mem, size_t size, int init, +* AstPlotVtab *vtab, const char *name, +* AstFrame *frame, const float *graphbox, +* const double *basebox ) + +* Class Membership: +* Plot initialiser. + +* Description: +* This function is provided for use by class implementations to initialise +* a new Plot object. It allocates memory (if necessary) to accommodate +* the Plot plus any additional data associated with the derived class. +* It then initialises a Plot structure at the start of this memory. If +* the "init" flag is set, it also initialises the contents of a virtual +* function table for a Plot at the start of the memory passed via the +* "vtab" parameter. + +* Parameters: +* mem +* A pointer to the memory in which the Plot is to be created. This +* must be of sufficient size to accommodate the Plot data +* (sizeof(Plot)) plus any data used by the derived class. If a value +* of NULL is given, this function will allocate the memory itself using +* the "size" parameter to determine its size. +* size +* The amount of memory used by the Plot (plus derived class data). +* This will be used to allocate memory if a value of NULL is given for +* the "mem" parameter. This value is also stored in the Plot +* structure, so a valid value must be supplied even if not required for +* allocating memory. +* init +* A logical flag indicating if the Plot's virtual function table is +* to be initialised. If this value is non-zero, the virtual function +* table will be initialised by this function. +* vtab +* Pointer to the start of the virtual function table to be associated +* with the new Plot. If NULL, the vtab associated with this class +* (Plot) will be used. +* name +* Pointer to a constant null-terminated character string which contains +* the name of the class to which the new object belongs (it is this +* pointer value that will subsequently be returned by the astGetClass +* method). +* frame +* A pointer to the Frame or Frameset to be annotated. +* graphbox +* A pointer to an array of 4 values giving the graphics coordinates +* of the bottom left and top right corners of a box on the graphics +* output device. The first pair of values should be the graphics +* coordinates of the bottom left corner of the box and the second +* pair of values are the graphics coordinates of the top right corner. +* The horizontal axis should be given first in each pair. +* basebox +* A pointer to an array of 4 values giving the coordinates in the +* supplied Frame or base Frame of the supplied FrameSet at the bottom +* left and top right corners of the box specified by parameter graphbox. +* These should be supplied in the same order as for parameter "graphbox". + +* Returned Value: +* A pointer to the new Plot. + +* Notes: +* - If the supplied Frame, or base Frame if a FrameSet was supplied, +* has more than 2 axes, then the sub-Frame defined by the first 2 axes +* is used. +* - The current Frame of the supplied FrameSet need not be 2-dimensional. +* - A null pointer will be returned if this function is invoked with the +* global error status set, or if it should fail for any reason. +*- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstFrame *baseframe; /* Pointer to base frame */ + AstFrame *graphicsframe; /* Pointer to graphics frame */ + AstFrameSet *fset0; /* The n-D FrameSet to be annotated */ + AstFrameSet *fset; /* The 2-D FrameSet to be annotated */ + AstPlot *new; /* Pointer to new Plot */ + AstWinMap *map; /* Mapping for converting bbox -> gbox */ + char *mess; /* Pointer to a descriptive message */ + double gbox[ 4 ]; /* Double precision version of "graphbox" */ + int axis; /* Axis index, 0 or 1 */ + int bi; /* Index of base frame */ + int ci; /* Index of current frame */ + int i; /* Loop count */ + int id; /* Plot object id */ + int naxes; /* No. of axes in frame */ + +/* Check the global status. */ + if ( !astOK ) return NULL; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(frame); + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + fset = NULL; + mess = NULL; + +/* If no vtab was supplied, use the vtab for this class (Plot). */ + if( !vtab ) { + vtab = &class_vtab; + if ( !class_init ) { + astInitPlotVtab( vtab, "Plot" ); + class_init = 1; + } + +/* If necessary, initialise the virtual function table. */ + } else if ( init ) { + astInitPlotVtab( vtab, name ); + } + +/* Initialise. */ + new = NULL; + baseframe = NULL; + +/* First of all we need to ensure that we have a FrameSet and a base + Frame on which to base the new Plot. If a NULL Frame pointer was + supplied, create a default 2-D Frame, and then create a FrameSet + containing just this default Frame. Also store a pointer to a + message which can be used to describe the object within error + messages. */ + if( !frame ){ + baseframe = astFrame( 2, "", status ); + fset = astFrameSet( baseframe, "", status ); + mess = "default 2-d Frame"; + +/* If an object was supplied, report an error if it is not a Frame or + an object derived from a Frame (such as a FrameSet). */ + } else if( !astIsAFrame( frame ) ){ + if( astOK ){ + astError( AST__BDOBJ, "astInitPlot(%s): Supplied Object (class '%s') " + "is not a Frame.", status, name, astGetClass( frame ) ); + } + +/* If the supplied object is a Plot or an object derived from a Plot (a Plot + is a sort of Frame and so will pass the above test), extract a + FrameSet from the Plot, and clear the Domain attribute for any existing + Frames which have Domain GRAPHICS. */ + } else if( astIsAPlot( frame ) ){ + fset0 = astFrameSet( frame, "", status ); + fset = astCopy( fset0 ); + fset0 = astAnnul( fset0 ); + + for( i = 0; i < astGetNframe( fset ); i++ ) { + graphicsframe = astGetFrame( fset, i ); + if( !strcmp( astGetDomain( graphicsframe ), "GRAPHICS" ) ) { + astClearDomain( graphicsframe ); + } + graphicsframe = astAnnul( graphicsframe ); + } + + baseframe = astGetFrame( fset, astGetBase( fset ) ); + mess = "base Frame of the supplied Plot"; + +/* If the object is not a FrameSet, create a FrameSet holding the + supplied Frame. If the Frame is not 2D, an extra 2D Frame is + included in the FrameSet derived from axes 1 and 2 of the supplied + Frame. This new Frame becomes the base Frame. */ + } else if( !astIsAFrameSet( frame ) ){ + fset0 = astFrameSet( frame, "", status ); + mess = "supplied Frame"; + fset = Fset2D( fset0, AST__BASE, status ); + fset0 = astAnnul( fset0 ); + baseframe = astGetFrame( fset, astGetBase( fset ) ); + +/* If a FrameSet was supplied, ensure it has a 2D base Frame. + If the supplied FrameSet is not 2D, then a new base Frame is + inserted into it which is derived from axes 1 and 2 of the + original base Frame. */ + } else { + fset = Fset2D( (AstFrameSet *) frame, AST__BASE, status ); + baseframe = astGetFrame( fset, astGetBase( fset ) ); + mess = "base Frame of the supplied FrameSet"; + } + +/* Check that there are 2 axes in the base frame of the FrameSet. */ + naxes = astGetNaxes( baseframe ); + if ( naxes != 2 && astOK ) { + astError( AST__NAXIN, "astInitPlot(%s): Number of axes (%d) in the %s " + "is invalid - this number should be 2.", status, name, naxes, mess ); + } + +/* Check that neither dimension of the graphbox is zero. */ + if( ( graphbox[ 2 ] == graphbox[ 0 ] || + graphbox[ 3 ] == graphbox[ 1 ] ) && astOK ){ + astError( AST__BADBX, "astInitPlot(%s): The plotting area has zero size " + "in the graphics world coordinate system.", status, name ); + } + +/* Check that neither dimension of the graphbox is bad. */ + if( astISBAD(graphbox[0]) || astISBAD(graphbox[1]) || + astISBAD(graphbox[2]) || astISBAD(graphbox[3]) ) { + astError( AST__BADBX, "astInitPlot(%s): The plotting area has undefined limits " + "in the graphics world coordinate system.", status, name ); + } + +/* Check that neither dimension of the basebox is zero. */ + if( astISBAD(basebox[2]) || astISBAD(basebox[0]) ) { + astError( AST__BADBX, "astInitPlot(%s): The limits of the horizontal " + "axis of the %s are undefined or bad.", status, name, name ); + } else if( astISBAD(basebox[3]) || astISBAD(basebox[1]) ) { + astError( AST__BADBX, "astInitPlot(%s): The limits of the vertical " + "axis of the %s are undefined or bad.", status, name, name ); + } + +/* Create a Frame which describes the graphics world coordinate system. */ + graphicsframe = astFrame( 2, + "Domain=GRAPHICS,Title=Graphical Coordinates", status ); + +/* Initialise a FrameSet structure (the parent class) as the first + component within the Plot structure, allocating memory if necessary. + The new FrameSet is initialised to hold the graphics Frame created + above. */ + new = (AstPlot *) astInitFrameSet( mem, size, 0, (AstFrameSetVtab *) vtab, + name, graphicsframe ); + + if ( astOK ) { + +/* Initialise the Plot data. */ +/* ----------------------------- */ + +/* Get a double precision version of "graphbox". */ + gbox[ 0 ] = (double) graphbox[ 0 ]; + gbox[ 1 ] = (double) graphbox[ 1 ]; + gbox[ 2 ] = (double) graphbox[ 2 ]; + gbox[ 3 ] = (double) graphbox[ 3 ]; + +/* Store the bounds in graphics coordinates of the clipping box, ensuring + that the low bound is lower than the high bound. Set flags to indicate + if the supplied bounds has to be reversed to do this (some graphics + system have the Y axis increasing from the top of the screen to the + bottom). */ + if( graphbox[ 0 ] <= graphbox[ 2 ] ){ + new->xlo = gbox[ 0 ]; + new->xhi = gbox[ 2 ]; + new->xrev = 0; + } else { + new->xhi = gbox[ 0 ]; + new->xlo = gbox[ 2 ]; + new->xrev = 1; + astSetDirection( graphicsframe, 0, 0 ); + } + if( graphbox[ 1 ] <= graphbox[ 3 ] ){ + new->ylo = gbox[ 1 ]; + new->yhi = gbox[ 3 ]; + new->yrev = 0; + } else { + new->yhi = gbox[ 1 ]; + new->ylo = gbox[ 3 ]; + new->yrev = 1; + astSetDirection( graphicsframe, 1, 0 ); + } + +/* Store the bounds of the Plot within the base Frame of the supplied + FrameSet. */ + new->bbox[ 0 ] = basebox[ 0 ]; + new->bbox[ 1 ] = basebox[ 1 ]; + new->bbox[ 2 ] = basebox[ 2 ]; + new->bbox[ 3 ] = basebox[ 3 ]; + +/* We initially assume that the base Frame of the supplied FrameSet is + mapped lineary onto the graphics frame. This may be changed later by + assigning values to the LogPlot attributes. Create a WinMap which + maps the base box (within the base Frame of the supplied FrameSet) + onto the graphics box. */ + map = astWinMap( 2, gbox, gbox + 2, basebox, basebox + 2, "", status ); + +/* Get the index of the current (physical) and base (pixel) Frames in + the supplied FrameSet. */ + bi = astGetBase( fset ); + ci = astGetCurrent( fset ); + +/* Temporarily set the current Frame to be the pixel frame. */ + astSetCurrent( fset, bi ); + +/* Add the supplied FrameSet into the Plot (i.e. FrameSet) created + earlier. This leaves the graphics frame with index 1 in the + returned Plot. We use the linear mapping initially. */ + astAddFrame( (AstFrameSet *) new, 1, map, fset ); + map = astAnnul( map ); + +/* Set the current Frame in the Plot to be the physical coordinate Frame + (with index incremented by one because the graphics Frame has been added). */ + astSetCurrent( (AstFrameSet *) new, ci + 1 ); + +/* Re-establish the original current Frame in the supplied FrameSet. */ + astSetCurrent( fset, ci ); + +/* Store a value of -1.0 for Tol to indicate that no value has yet been + set. This will cause a default value of 0.001 to be used. */ + new->tol = -1.0; + +/* Set up default clipping information which gives no clipping. */ + new->clip_frame = AST__NOFRAME; + new->clip_lbnd = NULL; + new->clip_ubnd = NULL; + new->clip_axes = 0; + +/* Is a grid covering the plotting area required? Store a value of -1 + to indicate that no value has yet been set. This will cause a default + value of 0 (no) to be used. */ + new->grid = -1; + +/* Are tick marks to be placed on both edges in a pair of opposite edges? + Store a value of -1 to indicate that no value has yet been set. This will + cause a default value of 1 (yes) to be used. */ + new->tickall = -1; + +/* Graphics context identifier */ + new->grfcontext = NULL; + new->grfcontextID = NULL; + +/* Shoudl ast Grid draw a boundary round the regions of valid coordinates? + Store a value of -1 to indicate that no value has yet been set. This will + cause a default value of 1 (yes) to be used. */ + new->border = -1; + +/* Should graphics be drawn invisible? Store a value of -1 to indicate that + no value has yet been set. This will cause a default value of 0 (no) to + be used. */ + new->invisible = -1; + +/* By default clip markers but not curves at the boundary of the plotting + area. This was the only behaviour available prior to the introduction of + the Clip attribute, and is chosen as the default to maintain backwards + compatibility. */ + new->clip = -1; + +/* Is clipping to be done using a logical OR operation between the axes? + Store a value of -1 to indicate that no value has yet been set. This will + cause a default value of 0 (no, i.e. a logical AND) to be used. */ + new->clipop = -1; + +/* Is the graphics interface registered using astGrfSet to be used? + Store a value of -1 to indicate that no value has yet been set. This will + cause a default value of 0 (no, i.e. use the graphics interface + selected at link-time) to be used. */ + new->grf = -1; + +/* Wrapper functions to call the drawing routines. These are the + default wrappers which call GRF routines written in C. Alternative + wrappers are defined in fplot.c for use with GRF routines written in + F77. */ + new->GAttr = CGAttrWrapper; + new->GBBuf = CGBBufWrapper; + new->GEBuf = CGEBufWrapper; + new->GFlush = CGFlushWrapper; + new->GLine = CGLineWrapper; + new->GMark = CGMarkWrapper; + new->GText = CGTextWrapper; + new->GCap = CGCapWrapper; + new->GTxExt = CGTxExtWrapper; + new->GScales = CGScalesWrapper; + new->GQch = CGQchWrapper; + + for( i = 0; i < AST__NGRFFUN; i++ ) new->grffun[i] = NULL; + new->grfstack = NULL; + new->grfnstack = 0; + +/* Is a title to be added to an annotated grid? Store a value of -1 to + indicate that no value has yet been set. This will cause a default value + of 1 (yes) to be used. */ + new->drawtitle = -1; + +/* Are escape sequences within text strings to be interpreted? If not, + they are printed literally. Store a value of -1 when not set. + This will cause a default value of 1 (yes) to be used. */ + new->escape = -1; + +/* A boolean attribute indicating where numerical labels are to be + placed; zero implies round the edges of the plotting area; non-zero + implies within the plotting area. The unset value of -9999 yields a + default of zero. */ + new->labelling = -9999; + +/* Graphics attributes. Default behaviour is to use the current values. */ + for( id = 0; id < AST__NPID; id++ ){ + new->style[ id ] = -1; + new->font[ id ] = -1; + new->colour[ id ] = -1; + new->width[ id ] = AST__BAD; + new->size[ id ] = AST__BAD; + } + +/* The space between the top edge and the grid title as a fraction of the + minimum dimension of the plotting area. Store AST__BAD to indicate that no + value has been set. This will cause a default of 0.05 to be used. */ + new->titlegap = AST__BAD; + +/* Initialise the protected Ink attribute so that visible ink is used. */ + new->ink = -1; + +/* A stack of AstGat pointers used to store the graphical attributes for + text within strings which include graphical escape sequences. */ + new->gat = NULL; + new->ngat = 0; + +/* Now set the attribute values for each axis. The arrays stored in the + Plot struture allow for 3 graphics axes (e.g. as used by a Plot3D) so + we initialise 3 axes here even though the Plot class only uses 2. */ + for( axis = 0; axis < 3; axis++ ) { + +/* Are curves to be drawn through the tick marks even if no grid is + produced? Store a value of -1 to indicate that no value has yet been + set. This will cause a default value of 1 (yes) to be used. */ + new->drawaxes[ axis ] = -1; + +/* Are adjacent numerical axis labels to be abbreviated by removing matching + leading fields? Store a value of -1 to indicate that no value has yet been + set. This will cause a default value of 1 (yes) to be used. */ + new->abbrev[ axis ] = -1; + +/* The length of the major tick marks as a fraction of the minimum + dimension of the plotting area. Store AST__BAD to indicate that no + value has been set. This will cause a default of 0.015 to be used. */ + new->majticklen[ axis ] = AST__BAD; + +/* The length of the minor tick marks as a fraction of the minimum + dimension of the plotting area. Store AST__BAD to indicate that no + value has been set. This will cause a default of 0.007 to be used. */ + new->minticklen[ axis ] = AST__BAD; + +/* Are numeric labels to be drawn upright? Store a value of -1 to indicate + that no value has yet been set. This will cause a default value of 0 (no) + to be used. */ + new->labelup[ axis ] = -1; + +/* The space between an axis and its numeric labels as a fraction of the + minimum dimension of the plotting area. Store AST__BAD to indicate that no + value has been set. This will cause a default of 0.01 to be used. */ + new->numlabgap[ axis ] = AST__BAD; + new->textlabgap[ axis ] = AST__BAD; + +/* The edges on which to put labels for axes 1 and 2. Store values of -1 + to indicate that no values have been set. This will cause default values + to be used. */ + new->edge[ axis ] = -1; + +/* The placement of labels within the plotting area will be done + automatically by default. */ + new->labelat[ axis ] = AST__BAD; + +/* The central tick is placed automatically by default. */ + new->centre[ axis ] = AST__BAD; + +/* The gap between tick marks and the number of minor tick marks will be + found automatically by default. */ + new->gap[ axis ] = AST__BAD; + new->loggap[ axis ] = AST__BAD; + new->mintick[ axis ] = -1; + +/* Both axes will be labelled by default. */ + new->numlab[ axis ] = -1; + new->textlab[ axis ] = -1; + new->labelunits[ axis ] = -1; + +/* Log/lin attributes. Default value is to use linear axes. */ + new->logplot[ axis ] = -1; + new->logticks[ axis ] = -1; + new->loglabel[ axis ] = -1; + +/* Initialise the components used to store the values actually used + for attributes which have dynamic defaults. */ + new->ulglb[ axis ] = new->loglabel[ axis ]; + new->ulgtk[ axis ] = new->logticks[ axis ]; + new->uloggap[ axis ] = new->loggap[ axis ]; + new->ugap[ axis ] = new->gap[ axis ]; + new->ucentre[ axis ] = new->centre[ axis ]; + new->uedge[ axis ] = new->edge[ axis ]; + new->ulblat[ axis ] = new->labelat[ axis ]; + new->ulbunit[ axis ] = new->labelunits[ axis ]; + new->umintk[ axis ] = new->mintick[ axis ]; + new->utxtlb[ axis ] = new->textlab[ axis ]; + new->umjtkln[ axis ] = new->majticklen[ axis ]; + +/* Initialise the arrays used to hold information describing the tick + marks that have been drawn for the axis. */ + new->majtickgx[ axis ] = NULL; + new->majtickgy[ axis ] = NULL; + new->majtickcount[ axis ] = 0; + new->mintickgx[ axis ] = NULL; + new->mintickgy[ axis ] = NULL; + new->mintickcount[ axis ] = 0; + new->nmajtickval[ axis ] = 0; + new->majtickval[ axis ] = NULL; + new->nmintickval[ axis ] = 0; + new->mintickval[ axis ] = NULL; + } + + new->ugrid = new->grid; + new->ulbling = new->labelling; + new->uborder = new->border; + + } + +/* Annul the frame. */ + graphicsframe = astAnnul( graphicsframe ); + +/* If an error occurred, clean up by deleting the new object. */ + if ( !astOK ) new = astDelete( new ); + +/* Annul the pointer to the base Frame and FrameSet. */ + baseframe = astAnnul( baseframe ); + fset = astAnnul( fset ); + +/* Return a pointer to the new object. */ + return new; +} + +AstPlot *astLoadPlot_( void *mem, size_t size, + AstPlotVtab *vtab, const char *name, + AstChannel *channel, int *status ) { +/* +*+ +* Name: +* astLoadPlot + +* Purpose: +* Load a Plot. + +* Type: +* Protected function. + +* Synopsis: +* #include "Plot.h" +* AstPlot *astLoadPlot( void *mem, size_t size, +* AstPlotVtab *vtab, const char *name, +* AstChannel *channel ) + +* Class Membership: +* Plot loader. + +* Description: +* This function is provided to load a new Plot using data read +* from a Channel. It first loads the data used by the parent class +* (which allocates memory if necessary) and then initialises a +* Plot structure in this memory, using data read from the input +* Channel. +* +* If the "init" flag is set, it also initialises the contents of a +* virtual function table for a Plot at the start of the memory +* passed via the "vtab" parameter. + + +* Parameters: +* mem +* A pointer to the memory into which the Plot is to be +* loaded. This must be of sufficient size to accommodate the +* Plot data (sizeof(Plot)) plus any data used by derived +* classes. If a value of NULL is given, this function will +* allocate the memory itself using the "size" parameter to +* determine its size. +* size +* The amount of memory used by the Plot (plus derived class +* data). This will be used to allocate memory if a value of +* NULL is given for the "mem" parameter. This value is also +* stored in the Plot structure, so a valid value must be +* supplied even if not required for allocating memory. +* +* If the "vtab" parameter is NULL, the "size" value is ignored +* and sizeof(AstPlot) is used instead. +* vtab +* Pointer to the start of the virtual function table to be +* associated with the new Plot. If this is NULL, a pointer +* to the (static) virtual function table for the Plot class +* is used instead. +* name +* Pointer to a constant null-terminated character string which +* contains the name of the class to which the new object +* belongs (it is this pointer value that will subsequently be +* returned by the astGetClass method). +* +* If the "vtab" parameter is NULL, the "name" value is ignored +* and a pointer to the string "Plot" is used instead. + +* Returned Value: +* A pointer to the new Plot. + +* Notes: +* - A null pointer will be returned if this function is invoked +* with the global error status set, or if it should fail for any +* reason. +*- +*/ + +#define KEY_LEN 50 /* Maximum length of a keyword */ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstPlot *new; /* Pointer to the new Plot */ + char buff[ KEY_LEN + 1 ]; /* Buffer for keyword string */ + char *text; /* Textual version of integer value */ + int axis; /* Zero based axis index */ + int id; /* Zero based graphical object id */ + int i; /* Loop count */ + int itick; /* Tick mark index */ + int nax; /* Number of base Frame axes */ + int ntick; /* Total number of ticks */ + +/* Initialise. */ + new = NULL; + +/* Check the global error status. */ + if ( !astOK ) return new; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(channel); + +/* If a NULL virtual function table has been supplied, then this is + the first loader to be invoked for this Plot. In this case the + Plot belongs to this class, so supply appropriate values to be + passed to the parent class loader (and its parent, etc.). */ + if ( !vtab ) { + size = sizeof( AstPlot ); + vtab = &class_vtab; + name = "Plot"; + +/* If required, initialise the virtual function table for this class. */ + if ( !class_init ) { + astInitPlotVtab( vtab, name ); + class_init = 1; + } + } + +/* Invoke the parent class loader to load data for all the ancestral + classes of the current one, returning a pointer to the resulting + partly-built Plot. */ + new = astLoadFrameSet( mem, size, (AstFrameSetVtab *) vtab, name, + channel ); + + if ( astOK ) { + +/* Get the number of graphics (base) frame axes - 2 for a Plot, 3 for a + Plot3D. */ + nax = astGetNin( new ); + +/* Read input data. */ +/* ================ */ +/* Request the input Channel to read all the input data appropriate to + this class into the internal "values list". */ + astReadClassData( channel, "Plot" ); + +/* Now read each individual data item from this list and use it to + initialise the appropriate instance variable(s) for this class. */ + +/* In the case of attributes, we first read the "raw" input value, + supplying the "unset" value as the default. If a "set" value is + obtained, we then use the appropriate (private) Set... member + function to validate and set the value properly. */ + +/* Tol. */ +/* ---- */ + new->tol = astReadDouble( channel, "tol", -1.0 ); + if ( TestTol( new, status ) ) SetTol( new, new->tol, status ); + +/* Grid. */ +/* ----- */ + new->grid = astReadInt( channel, "grid", -1 ); + if ( TestGrid( new, status ) ) SetGrid( new, new->grid, status ); + +/* TickAll. */ +/* -------- */ + new->tickall = astReadInt( channel, "tckall", -1 ); + if ( TestTickAll( new, status ) ) SetTickAll( new, new->tickall, status ); + +/* ForceExterior. */ +/* -------- */ + new->forceexterior = astReadInt( channel, "frcext", -1 ); + if ( TestForceExterior( new, status ) ) SetForceExterior( new, new->forceexterior, status ); + +/* Invisible. */ +/* ---------- */ + new->invisible = astReadInt( channel, "invsbl", -1 ); + if ( TestInvisible( new, status ) ) SetInvisible( new, new->invisible, status ); + +/* Border. */ +/* -------- */ + new->border = astReadInt( channel, "border", -1 ); + if ( TestBorder( new, status ) ) SetBorder( new, new->border, status ); + +/* ClipOp. */ +/* ------- */ + new->clipop = astReadInt( channel, "clpop", -1 ); + if ( TestClipOp( new, status ) ) SetClipOp( new, new->clipop, status ); + +/* Clip. */ +/* ----- */ + new->clip = astReadInt( channel, "clip", -1 ); + if ( TestClip( new, status ) ) SetClip( new, new->clip, status ); + +/* DrawTitle. */ +/* --------- */ + new->drawtitle = astReadInt( channel, "drwttl", -1 ); + if ( TestDrawTitle( new, status ) ) SetDrawTitle( new, new->drawtitle, status ); + +/* LabelUp(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "lblup%d", axis + 1 ); + new->labelup[ axis ] = astReadInt( channel, buff, -1 ); + if ( TestLabelUp( new, axis, status ) ) SetLabelUp( new, axis, + new->labelup[ axis ], status ); + } + +/* LogPlot(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "lgplt%d", axis + 1 ); + new->logplot[ axis ] = astReadInt( channel, buff, -1 ); + if ( TestLogPlot( new, axis, status ) ) SetLogPlot( new, axis, + new->logplot[ axis ], status ); + } + +/* LogTicks(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "lgtck%d", axis + 1 ); + new->logticks[ axis ] = astReadInt( channel, buff, -1 ); + if ( TestLogTicks( new, axis, status ) ) SetLogTicks( new, axis, + new->logticks[ axis ], status ); + } + +/* LogLabel(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "lglbl%d", axis + 1 ); + new->loglabel[ axis ] = astReadInt( channel, buff, -1 ); + if ( TestLogLabel( new, axis, status ) ) SetLogLabel( new, axis, + new->loglabel[ axis ], status ); + } + +/* DrawAxes. */ +/* --------- */ + new->drawaxes[ 0 ] = astReadInt( channel, "drwaxs", -1 ); + + if( new->drawaxes[ 0 ] != -1 ) { + new->drawaxes[ 1 ] = new->drawaxes[ 0 ]; + if ( TestDrawAxes( new, 0, status ) ) SetDrawAxes( new, 0, new->drawaxes[ 0 ], status ); + if ( TestDrawAxes( new, 1, status ) ) SetDrawAxes( new, 1, new->drawaxes[ 1 ], status ); + + } else { + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "drwaxs%d", axis + 1 ); + new->drawaxes[ axis ] = astReadInt( channel, buff, -1 ); + if ( TestDrawAxes( new, axis, status ) ) SetDrawAxes( new, axis, + new->drawaxes[ axis ], status ); + } + } + +/* Abbrev. */ +/* ------- */ + new->abbrev[ 0 ] = astReadInt( channel, "abbrv", -1 ); + + if( new->abbrev[ 0 ] != -1 ) { + new->abbrev[ 1 ] = new->abbrev[ 0 ]; + if ( TestAbbrev( new, 0, status ) ) SetAbbrev( new, 0, new->abbrev[ 0 ], status ); + if ( TestAbbrev( new, 1, status ) ) SetAbbrev( new, 1, new->abbrev[ 1 ], status ); + + } else { + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "abbrv%d", axis + 1 ); + new->abbrev[ axis ] = astReadInt( channel, buff, -1 ); + if ( TestAbbrev( new, axis, status ) ) SetAbbrev( new, axis, + new->abbrev[ axis ], status ); + } + } + + +/* Escape. */ +/* ------- */ + new->escape = astReadInt( channel, "escape", -1 ); + if ( TestEscape( new, status ) ) SetEscape( new, new->escape, status ); + +/* LabelAt(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "lblat%d", axis + 1 ); + new->labelat[ axis ] = astReadDouble( channel, buff, AST__BAD ); + if ( TestLabelAt( new, axis, status ) ) SetLabelAt( new, axis, + new->labelat[ axis ], status ); + } + +/* Centre(axis). */ +/* ------------ */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "cen%d", axis + 1 ); + new->centre[ axis ] = astReadDouble( channel, buff, AST__BAD ); + if ( TestCentre( new, axis, status ) ) SetCentre( new, axis, + new->centre[ axis ], status ); + } + +/* Gap(axis). */ +/* ---------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "gap%d", axis + 1 ); + new->gap[ axis ] = astReadDouble( channel, buff, AST__BAD ); + if ( TestGap( new, axis, status ) ) SetGap( new, axis, new->gap[ axis ], status ); + } + +/* LogGap(axis). */ +/* ------------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "lggap%d", axis + 1 ); + new->loggap[ axis ] = astReadDouble( channel, buff, AST__BAD ); + if ( TestLogGap( new, axis, status ) ) SetLogGap( new, axis, new->loggap[ axis ], status ); + } + +/* NumLabGap(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "nmgap%d", axis + 1 ); + new->numlabgap[ axis ] = astReadDouble( channel, buff, AST__BAD ); + if ( TestNumLabGap( new, axis, status ) ) SetNumLabGap( new, axis, + new->numlabgap[ axis ], status ); + } + +/* TextLabGap(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "txgap%d", axis + 1 ); + new->textlabgap[ axis ] = astReadDouble( channel, buff, AST__BAD ); + if ( TestTextLabGap( new, axis, status ) ) SetTextLabGap( new, axis, + new->textlabgap[ axis ], status ); + } + +/* NumLab(axis). */ +/* ---------------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "nmlbl%d", axis + 1 ); + new->numlab[ axis ] = astReadInt( channel, buff, -1 ); + if ( TestNumLab( new, axis, status ) ) SetNumLab( new, axis, + new->numlab[ axis ], status ); + } + +/* MinTick(axis). */ +/* --------------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "mntks%d", axis + 1 ); + new->mintick[ axis ] = astReadInt( channel, buff, -1 ); + if ( TestMinTick( new, axis, status ) ) SetMinTick( new, axis, + new->mintick[ axis ], status ); + } + +/* TextLab(axis). */ +/* -------------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "txlbl%d", axis + 1 ); + new->textlab[ axis ] = astReadInt( channel, buff, -1 ); + if ( TestTextLab( new, axis, status ) ) SetTextLab( new, axis, + new->textlab[ axis ], status ); + } + +/* LabelUnits(axis). */ +/* --------------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "lbunt%d", axis + 1 ); + new->labelunits[ axis ] = astReadInt( channel, buff, -1 ); + if ( TestLabelUnits( new, axis, status ) ) SetLabelUnits( new, axis, + new->labelunits[ axis ], status ); + } + +/* Style(object). */ +/* ------------ */ + for( id = 0; id < AST__NPID; id++ ){ + (void) sprintf( buff, "style%d", id + 1 ); + new->style[ id ] = astReadInt( channel, buff, -1 ); + if ( TestStyle( new, id, status ) ) SetStyle( new, id, new->style[ id ], status ); + } + +/* Font(object). */ +/* ----------- */ + for( id = 0; id < AST__NPID; id++ ){ + (void) sprintf( buff, "font%d", id + 1 ); + new->font[ id ] = astReadInt( channel, buff, -1 ); + if ( TestFont( new, id, status ) ) SetFont( new, id, new->font[ id ], status ); + } + +/* Colour(object). */ +/* --------------- */ + for( id = 0; id < AST__NPID; id++ ){ + (void) sprintf( buff, "col%d", id + 1 ); + new->colour[ id ] = astReadInt( channel, buff, -1 ); + if ( TestColour( new, id, status ) ) SetColour( new, id, new->colour[ id ], status ); + } + +/* Width(object). */ +/* ------------ */ + for( id = 0; id < AST__NPID; id++ ){ + (void) sprintf( buff, "width%d", id + 1 ); + new->width[ id ] = astReadDouble( channel, buff, AST__BAD ); + if ( TestWidth( new, id, status ) ) SetWidth( new, id, new->width[ id ], status ); + } + +/* Size(object). */ +/* ----------- */ + for( id = 0; id < AST__NPID; id++ ){ + (void) sprintf( buff, "size%d", id + 1 ); + new->size[ id ] = astReadDouble( channel, buff, AST__BAD ); + if ( TestSize( new, id, status ) ) SetSize( new, id, new->size[ id ], status ); + } + +/* TitleGap. */ +/* --------- */ + new->titlegap = astReadDouble( channel, "ttlgap", AST__BAD ); + if ( TestTitleGap( new, status ) ) SetTitleGap( new, new->titlegap, status ); + +/* MajTickLen. */ +/* ----------- */ +/* Retained in order to read old Plots - new Plots use MajTickLen(axis). */ + new->majticklen[ 0 ] = astReadDouble( channel, "mjtkln", AST__BAD ); + if( new->majticklen[ 0 ] != AST__BAD ) { + new->majticklen[ 1 ] = new->majticklen[ 0 ]; + if ( TestMajTickLen( new, 0, status ) ) SetMajTickLen( new, 0, new->majticklen[ 0 ], status ); + if ( TestMajTickLen( new, 1, status ) ) SetMajTickLen( new, 1, new->majticklen[ 1 ], status ); + +/* MajTickLen(axis). */ +/* ----------------- */ + } else { + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "mjtkln%d", axis + 1 ); + new->majticklen[ axis ] = astReadDouble( channel, buff, AST__BAD ); + if ( TestMajTickLen( new, axis, status ) ) SetMajTickLen( new, axis, + new->majticklen[ axis ], status ); + } + } + +/* MinTickLen. */ +/* ----------- */ +/* Retained in order to read old Plots - new Plots use MinTickLen(axis). */ + new->minticklen[ 0 ] = astReadDouble( channel, "mntkln", AST__BAD ); + if( new->minticklen[ 0 ] != AST__BAD ) { + new->minticklen[ 1 ] = new->minticklen[ 0 ]; + if ( TestMinTickLen( new, 0, status ) ) SetMinTickLen( new, 0, new->minticklen[ 0 ], status ); + if ( TestMinTickLen( new, 1, status ) ) SetMinTickLen( new, 1, new->minticklen[ 1 ], status ); + +/* MinTickLen(axis). */ +/* ----------------- */ + } else { + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "mntkln%d", axis + 1 ); + new->minticklen[ axis ] = astReadDouble( channel, buff, AST__BAD ); + if ( TestMinTickLen( new, axis, status ) ) SetMinTickLen( new, axis, + new->minticklen[ axis ], status ); + } + } + +/* Labelling. */ +/* ---------- */ + text = astReadString( channel, "lbling", " " ); + if( astOK && strcmp( text, " " ) ) { + new->labelling = FindString( 2, xlbling, text, + "the Plot component 'Lbling'", + "astRead", astGetClass( channel ), status ); + } else { + new->labelling = -9999; + } + if ( TestLabelling( new, status ) ) SetLabelling( new, new->labelling, status ); + text = astFree( text ); + +/* Edge(axis). */ +/* ----------- */ + for( axis = 0; axis < nax; axis++ ){ + (void) sprintf( buff, "edge%d", axis + 1 ); + text = astReadString( channel, buff, " " ); + if( astOK && strcmp( text, " " ) ) { + new->edge[ axis ] = FindString( 4, xedge, text, + "the Plot component 'Edge'", + "astRead", astGetClass( channel ), status ); + } else { + new->edge[ axis ] = -1; + } + if ( TestEdge( new, axis, status ) ) SetEdge( new, axis, + new->edge[ axis ], status ); + text = astFree( text ); + } + +/* Now do instance variables which are not attributes. */ +/* =================================================== */ + +/* We have no graphics context. */ + new->grfcontext = NULL; + new->grfcontextID = NULL; + +/* Initialise the protected Ink attribute so that visible ink is used. */ + new->ink = -1; + +/* The number of bounds supplied for the clipping volume. */ + new->clip_axes = astReadInt( channel, "clpaxs", 0 ); + if ( new->clip_axes < 0 ) new->clip_axes = 0; + +/* The index of the clipping Frame within the Plot. */ + new->clip_frame = astReadInt( channel, "clpfrm", AST__NOFRAME ); + +/* If necessary, allocate memory to hold the bounds of the clipping volume. */ + if( new->clip_axes > 0 ){ + new->clip_lbnd = astMalloc( sizeof( double ) * (size_t) new->clip_axes ); + new->clip_ubnd = astMalloc( sizeof( double ) * (size_t) new->clip_axes ); + +/* If an error occurs, ensure that all allocated memory is freed. */ + if ( !astOK ) { + new->clip_lbnd = (double *) astFree( (void *) new->clip_lbnd ); + new->clip_ubnd = (double *) astFree( (void *) new->clip_ubnd ); + +/* Otherwise, store the bounds. Use extreme defaults if no values are + available. */ + } else { + for( axis = 0; axis < new->clip_axes; axis++ ){ + (void) sprintf( buff, "clplb%d", axis + 1 ); + new->clip_lbnd[ axis ] = astReadDouble( channel, buff, -DBL_MAX ); + + (void) sprintf( buff, "clpub%d", axis + 1 ); + new->clip_ubnd[ axis ] = astReadDouble( channel, buff, DBL_MAX ); + } + } + +/* If there are no clipping axes, store NULL pointers for the bounds + arrays. */ + } else { + new->clip_lbnd = NULL; + new->clip_ubnd = NULL; + } + +/* The bounds of the plotting area in graphics coords. */ + new->xlo = astReadDouble( channel, "xlo", 0.0 ); + new->xhi = astReadDouble( channel, "xhi", 1.0 ); + new->ylo = astReadDouble( channel, "ylo", 0.0 ); + new->yhi = astReadDouble( channel, "yhi", 1.0 ); + +/* Axis reversal flags. */ + new->xrev = astReadInt( channel, "xrev", 0 ); + new->yrev = astReadInt( channel, "yrev", 0 ); + +/* The bounds of the plotting area in the base Frame of the FrameSet + supplied when the Plot was constructed. */ + new->bbox[ 0 ] = astReadDouble( channel, "xb1", AST__BAD ); + new->bbox[ 1 ] = astReadDouble( channel, "yb1", AST__BAD ); + new->bbox[ 2 ] = astReadDouble( channel, "xb2", AST__BAD ); + new->bbox[ 3 ] = astReadDouble( channel, "yb2", AST__BAD ); + +/* Grf. */ + new->grf = -1; + new->GAttr = CGAttrWrapper; + new->GBBuf = CGBBufWrapper; + new->GEBuf = CGEBufWrapper; + new->GFlush = CGFlushWrapper; + new->GLine = CGLineWrapper; + new->GMark = CGMarkWrapper; + new->GText = CGTextWrapper; + new->GCap = CGCapWrapper; + new->GTxExt = CGTxExtWrapper; + new->GScales = CGScalesWrapper; + new->GQch = CGQchWrapper; + for( i = 0; i < AST__NGRFFUN; i++ ) new->grffun[i] = NULL; + new->grfstack = NULL; + new->grfnstack = 0; + +/* A stack of AstGat pointers used to store the graphical attributes for + text within strings which include graphical escape sequences. */ + new->gat = NULL; + new->ngat = 0; + +/* Arrays holding user-specified major and minot tick mark values. */ + for( axis = 0; axis < 3; axis++ ) { + sprintf( buff, "nmjtk%d", axis + 1 ); + ntick = astReadInt( channel, buff, 0 ); + new->nmajtickval[ axis ] = ntick; + new->majtickval[ axis ] = astMalloc( ntick*sizeof( double ) ); + + for( itick = 0; itick < ntick; itick++ ) { + sprintf( buff, "mjtk%d_%d", axis + 1, itick + 1 ); + new->majtickval[ axis ][ itick ] = astReadDouble( channel, buff, + AST__BAD ); + } + + sprintf( buff, "nmntk%d", axis + 1 ); + ntick = astReadInt( channel, buff, 0 ); + new->nmintickval[ axis ] = ntick; + new->mintickval[ axis ] = astMalloc( ntick*sizeof( double ) ); + + for( itick = 0; itick < ntick; itick++ ) { + sprintf( buff, "mntk%d_%d", axis + 1, itick + 1 ); + new->mintickval[ axis ][ itick ] = astReadDouble( channel, buff, + AST__BAD ); + } + + } + +/* Initialise the arrays used to hold information describing the tick + marks that have already been drawn for each axis. */ + for( axis = 0; axis < 3; axis++ ) { + new->majtickgx[ axis ] = NULL; + new->majtickgy[ axis ] = NULL; + new->majtickcount[ axis ] = 0; + new->mintickgx[ axis ] = NULL; + new->mintickgy[ axis ] = NULL; + new->mintickcount[ axis ] = 0; + } + +/* If an error occurred, clean up by deleting the new Plot. */ + if ( !astOK ) new = astDelete( new ); + } + +/* Return the new Plot pointer. */ + return new; +} + +/* Virtual function interfaces. */ +/* ============================ */ +/* These provide the external interface to the virtual functions defined by + this class. Each simply checks the global error status and then locates and + executes the appropriate member function, using the function pointer stored + in the object's virtual function table (this pointer is located using the + astMEMBER macro defined in "object.h"). + Note that the member function may not be the one defined here, as it may + have been over-ridden by a derived class. However, it should still have the + same interface. */ + +void astBBuf_( AstPlot *this, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,BBuf))(this, status ); +} + +int astBorder_( AstPlot *this, int *status ){ + if( !astOK ) return 0; + return (**astMEMBER(this,Plot,Border))(this, status ); +} + +void astBoundingBox_( AstPlot *this, float lbnd[2], float ubnd[2], int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,BoundingBox))(this,lbnd,ubnd, status ); +} + +void astClip_( AstPlot *this, int iframe, const double lbnd[], +const double ubnd[], int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,Clip))(this,iframe,lbnd,ubnd, status ); +} + +void astGrid_( AstPlot *this, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,Grid))(this, status ); +} + +int astCvBrk_( AstPlot *this, int ibrk, double *brk, double *vbrk, + double *len, int *status ){ + if( !astOK ) return 0; + return (**astMEMBER(this,Plot,CvBrk))(this,ibrk,brk,vbrk,len, status ); +} + +void astEBuf_( AstPlot *this, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,EBuf))(this, status ); +} + +void astMirror_( AstPlot *this, int axis, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,Mirror))(this,axis, status ); +} + +AstPointSet *astGetDrawnTicks_( AstPlot *this, int axis, int major, int *status ){ + if( !astOK ) return NULL; + return (**astMEMBER(this,Plot,GetDrawnTicks))(this,axis,major, status ); +} + +void astSetTickValues_( AstPlot *this, int axis, int nmajor, double *major, + int nminor, double *minor, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,SetTickValues))(this,axis,nmajor,major,nminor,minor, status ); +} + +void astCopyPlotDefaults_( AstPlot *this, int axis, AstPlot *dplot, + int daxis, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,CopyPlotDefaults))(this,axis,dplot,daxis, status ); +} + +int astGetLabelUnits_( AstPlot *this, int axis, int *status ){ + if( !astOK ) return 0; + return (**astMEMBER(this,Plot,GetLabelUnits))(this,axis, status ); +} + +void astMark_( AstPlot *this, int nmark, int ncoord, int indim, + const double *in, int type, int *status ) { + if ( !astOK ) return; + (**astMEMBER(this,Plot,Mark))( this, nmark, ncoord, indim, in, type, status ); +} + +void astText_( AstPlot *this, const char *text, const double pos[], + const float up[], const char *just, int *status ){ + if ( !astOK ) return; + (**astMEMBER(this,Plot,Text))( this, text, pos, up, just, status ); +} + +void astGridLine_( AstPlot *this, int axis, const double start[], double length, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,GridLine))(this,axis,start,length, status ); +} + +void astCurve_( AstPlot *this, const double start[], const double finish[], int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,Curve))(this,start,finish, status ); +} + +void astGenCurve_( AstPlot *this, AstMapping *map, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,GenCurve))(this,map, status ); +} + +void astPolyCurve_( AstPlot *this, int npoint, int ncoord, int dim, + const double *in, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,PolyCurve))(this,npoint,ncoord,dim,in, status ); +} + +void astRegionOutline_( AstPlot *this, AstRegion *region, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,RegionOutline))(this,region,status); +} + +void astGrfSet_( AstPlot *this, const char *name, AstGrfFun fun, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,GrfSet))(this,name,fun, status ); +} + +void astGrfPush_( AstPlot *this, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,GrfPush))(this, status ); +} + +void astGrfPop_( AstPlot *this, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,GrfPop))(this, status ); +} + +void astGrfWrapper_( AstPlot *this, const char *name, AstGrfWrap wrapper, int *status ){ + if( !astOK ) return; + (**astMEMBER(this,Plot,GrfWrapper))(this,name,wrapper, status ); +} + +void astSetLogPlot_( AstPlot *this, int axis, int value, int *status ) { + if ( !astOK ) return; + (**astMEMBER(this,Plot,SetLogPlot))( this, axis, value, status ); +} + +void astClearLogPlot_( AstPlot *this, int axis, int *status ) { + if ( !astOK ) return; + (**astMEMBER(this,Plot,ClearLogPlot))( this, axis, status ); +} + +AstKeyMap *astGetGrfContext_( AstPlot *this, int *status ) { + if ( !astOK ) return NULL; + return (**astMEMBER(this,Plot,GetGrfContext))( this, status ); +} + +/* Special public interface functions. */ +/* =================================== */ +/* These provide the public interface to certain special functions + whose public interface cannot be handled using macros (such as + astINVOKE) alone. In general, they are named after the + corresponding protected version of the function, but with "Id" + appended to the name. */ + +/* Special interface function implementations. */ +/* ------------------------------------------- */ +AstPlot *astPlotId_( void *frame_void, const float graphbox[4], + const double basebox[4], const char *options, ... ) { +/* +*++ +* Name: +c astPlot +f AST_PLOT + +* Purpose: +* Create a Plot. + +* Type: +* Public function. + +* Synopsis: +c #include "plot.h" +c AstPlot *astPlot( AstFrame *frame, const float graphbox[ 4 ], +c const double basebox[ 4 ], const char *options, ... ) +f RESULT = AST_PLOT( FRAME, GRAPHBOX, BASEBOX, OPTIONS, STATUS ) + +* Class Membership: +* Plot constructor. + +* Description: +* This function creates a new Plot and optionally initialises its +* attributes. +* +* A Plot is a specialised form of FrameSet, in which the base +* Frame describes a "graphical" coordinate system and is +* associated with a rectangular plotting area in the underlying +* graphics system. This plotting area is where graphical output +* appears. It is defined when the Plot is created. +* +* The current Frame of a Plot describes a "physical" coordinate +* system, which is the coordinate system in which plotting +* operations are specified. The results of each plotting operation +* are automatically transformed into graphical coordinates so as +* to appear in the plotting area (subject to any clipping which +* may be in effect). +* +* Because the Mapping between physical and graphical coordinates +* may often be non-linear, or even discontinuous, most plotting +* does not result in simple straight lines. The basic plotting +* element is therefore not a straight line, but a geodesic curve +c (see astCurve). A Plot also provides facilities for drawing +c markers or symbols (astMark), text (astText) and grid lines +c (astGridLine). It is also possible to draw curvilinear axes with +c optional coordinate grids (astGrid). +f (see AST_CURVE). A Plot also provides facilities for drawing +f markers or symbols (AST_MARK), text (AST_TEXT) and grid lines +f (AST_GRIDLINE). It is also possible to draw curvilinear axes +f with optional coordinate grids (AST_GRID). +* A range of Plot attributes is available to allow precise control +* over the appearance of graphical output produced by these +c functions. +f routines. +* +* You may select different physical coordinate systems in which to +* plot (including the native graphical coordinate system itself) +* by selecting different Frames as the current Frame of a Plot, +* using its Current attribute. You may also set up clipping (see +c astClip) to limit the extent of any plotting you perform, and +f AST_CLIP) to limit the extent of any plotting you perform, and +* this may be done in any of the coordinate systems associated +* with the Plot, not necessarily the one you are plotting in. +* +* Like any FrameSet, a Plot may also be used as a Frame. In this +* case, it behaves like its current Frame, which describes the +* physical coordinate system. +* +* When used as a Mapping, a Plot describes the inter-relation +* between graphical coordinates (its base Frame) and physical +* coordinates (its current Frame). It differs from a normal +* FrameSet, however, in that an attempt to transform points which +* lie in clipped areas of the Plot will result in bad coordinate +* values (AST__BAD). + +* Parameters: +c frame +f FRAME = INTEGER (Given) +* Pointer to a Frame describing the physical coordinate system +* in which to plot. A pointer to a FrameSet may also be given, +* in which case its current Frame will be used to define the +* physical coordinate system and its base Frame will be mapped +* on to graphical coordinates (see below). +* +* If a null Object pointer (AST__NULL) is given, a default +* 2-dimensional Frame will be used to describe the physical +* coordinate system. Labels, etc. may then be attached to this +* by setting the appropriate Frame attributes +* (e.g. Label(axis)) for the Plot. +c graphbox +f GRAPHBOX( 4 ) = REAL (Given) +* An array giving the position and extent of the plotting area +* (on the plotting surface of the underlying graphics system) +* in which graphical output is to appear. This must be +* specified using graphical coordinates appropriate to the +* underlying graphics system. +* +* The first pair of values should give the coordinates of the +* bottom left corner of the plotting area and the second pair +* should give the coordinates of the top right corner. The +* coordinate on the horizontal axis should be given first in +* each pair. Note that the order in which these points are +* given is important because it defines up, down, left and +* right for subsequent graphical operations. +c basebox +f BASEBOX( 4 ) = DOUBLE PRECISION (Given) +* An array giving the coordinates of two points in the supplied +* Frame (or in the base Frame if a FrameSet was supplied) which +* correspond to the bottom left and top right corners of the +* plotting area, as specified above. This range of coordinates +* will be mapped linearly on to the plotting area. The +* coordinates should be given in the same order as above. +c options +f OPTIONS = CHARACTER * ( * ) (Given) +c Pointer to a null-terminated string containing an optional +c comma-separated list of attribute assignments to be used for +c initialising the new Plot. The syntax used is identical to +c that for the astSet function and may include "printf" format +c specifiers identified by "%" symbols in the normal way. +c If no initialisation is required, a zero-length string may be +c supplied. +f A character string containing an optional comma-separated +f list of attribute assignments to be used for initialising the +f new Plot. The syntax used is identical to that for the +f AST_SET routine. If no initialisation is required, a blank +f value may be supplied. +c ... +c If the "options" string contains "%" format specifiers, then +c an optional list of additional arguments may follow it in +c order to supply values to be substituted for these +c specifiers. The rules for supplying these are identical to +c those for the astSet function (and for the C "printf" +c function). +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Returned Value: +c astPlot() +f AST_PLOT +* A pointer to the new Plot. + +* Notes: +* - The base Frame of the returned Plot will be a new Frame which +* is created by this function to represent the coordinate system +* of the underlying graphics system (graphical coordinates). It is +* given a Frame index of 1 within the Plot. The choice of base +* Frame (Base attribute) should not, in general, be changed once a +* Plot has been created (although you could use this as a way of +* moving the plotting area around on the plotting surface). +c - If a Frame is supplied (via the "frame" pointer), then it +f - If a Frame is supplied (via the FRAME pointer), then it +* becomes the current Frame of the new Plot and is given a Frame +* index of 2. +c - If a FrameSet is supplied (via the "frame" pointer), then +f - If a FrameSet is supplied (via the FRAME pointer), then +* all the Frames within this FrameSet become part of the new Plot +* (where their Frame indices are increased by 1), with the +* FrameSet's current Frame becoming the current Frame of the Plot. +* - If a null Object pointer (AST__NULL) is supplied (via the +c "frame" pointer), then the returned Plot will contain two +f FRAME pointer), then the returned Plot will contain two +* Frames, both created by this function. The base Frame will +* describe graphics coordinates (as above) and the current Frame +* will be a basic Frame with no attributes set (this will +* therefore give default values for such things as the Plot Title +* and the Label on each axis). Physical coordinates will be mapped +* linearly on to graphical coordinates. +* - An error will result if the Frame supplied (or the base Frame +* if a FrameSet was supplied) is not 2-dimensional. +* - A null Object pointer (AST__NULL) will be returned if this +c function is invoked with the AST error status set, or if it +f function is invoked with STATUS set to an error value, or if it +* should fail for any reason. +*-- + +* Implementation Notes: +* - This function implements the external (public) interface to +* the astPlot constructor function. It returns an ID value +* (instead of a true C pointer) to external users, and must be +* provided because astPlot_ has a variable argument list which +* cannot be encapsulated in a macro (where this conversion would +* otherwise occur). +* - Because no checking or casting of arguments is performed +* before the function is invoked, the "frame" parameter is of type +* (void *) and is converted from an ID value to a pointer and +* validated within the function itself. +* - The variable argument list also prevents this function from +* invoking astPlot_ directly, so it must be a +* re-implementation of it in all respects, except for the +* conversions between IDs and pointers on input/output of Objects. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstFrame *frame; /* Pointer to Frame structure */ + AstPlot *new; /* Pointer to new Plot */ + va_list args; /* Variable argument list */ + int *status; /* Pointer to inherited status value */ + +/* Get apointer to the inherited status value. */ + status = astGetStatusPtr; + +/* Check the global status. */ + if ( !astOK ) return NULL; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Initialise variables to avoid "used of uninitialised variable" + messages from dumb compilers. */ + new = NULL; + +/* Obtain a Frame pointer from any ID supplied and validate the + pointer to ensure it identifies a valid Frame. */ + if( frame_void ){ + frame = astVerifyFrame( astMakePointer( frame_void ) ); + } else { + frame = NULL; + } + +/* Check the pointer can be used. */ + if ( astOK ) { + +/* Initialise the Plot, allocating memory and initialising the + virtual function table as well if necessary. */ + new = astInitPlot( NULL, sizeof( AstPlot ), !class_init, + &class_vtab, "Plot", frame, graphbox, + basebox ); + +/* If successful, note that the virtual function table has been + initialised. */ + if ( astOK ) { + class_init = 1; + +/* Obtain the variable argument list and pass it along with the + options string to the astVSet method to initialise the new + Plot's attributes. */ + + va_start( args, options ); + astVSet( new, options, NULL, args ); + va_end( args ); + +/* If an error occurred, clean up by deleting the new object. */ + if ( !astOK ) new = astDelete( new ); + } + } + +/* Return an ID value for the new Plot. */ + return astMakeId( new ); + +} + + + + |