diff options
author | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
---|---|---|
committer | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
commit | 40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch) | |
tree | 4464880c571602d54f6ae114729bf62a89518057 /sys/plio | |
download | iraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz |
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'sys/plio')
121 files changed, 12419 insertions, 0 deletions
diff --git a/sys/plio/PLIO.hlp b/sys/plio/PLIO.hlp new file mode 100644 index 00000000..16e23dfc --- /dev/null +++ b/sys/plio/PLIO.hlp @@ -0,0 +1,1341 @@ +.help PLIO Feb88 "Pixel List Package Design" +.ce +\fBThe IRAF Pixel List Package\fR +.ce +and +.ce +\fBIMIO Extensions to Support Image Masks\fR +.ce +Doug Tody +.ce +February, 1988 +.ce +(Revised June 1988) + + +.NH +Introduction + + The pixel list package is a general package for flagging individual pixels +or regions of an image, to mark some subset of the pixels in an image. +This may be done to flag bad pixels, or to identify those regions of an image +to be processed by some applications program. When the pixel list package is +used to flag the bad pixels in an image we call this a \fBbad pixel mask\fR, +or BPM. When used to identify the regions of an image to be processed (or +ignored), we call the list a \fBregion mask\fR. + +A pixel list may be viewed conceptually as either a list or an image; the list +is merely the compressed form of a virtual \fBmask image\fR. Storing a mask +image as a list has two major advantages. +.ls +.ls [1] +Storage efficiency. Simple masks may be stored very compactly, e.g., as small +arrays stored directly in an image header, or in a separate mask file or +database. +.le +.ls [2] +Runtime efficiency. Storing a mask in list form has the advantage that one +can determine very quickly whether or not a given region of the image (e.g., +an image line) contains any pixels in the mask. The alternative, given a +fully populated mask image (or flagging the pixels directly in the data image), +requires that one examine every pixel in the mask image, which is very +inefficient for simple masks. +.le +.le + +The pixel list technique for implementing image masks is the most efficient +choice only for simple or moderately complex masks. As a mask image increases +in complexity there eventually comes a point where it would be simpler and +more efficient to use a conventional raster image to store the mask. +For example, if one wishes to associate a flag value (such as a weight) with +every pixel in an image, and the flag values vary rapidly in value across the +image, a separate image should probably be used (except that other forms of +data compression may be possible; the IRAF \fInoise function package\fR +addresses one aspect of this problem). + +The pixel list related software is subdivided into two parts, the pixel list +package itself, and the extensions to IMIO to make use of the pixel list +package. The pixel list package in itself is independent of IMIO and may be +used separately. + +.NH +IMIO Support for Pixel Lists + + Most image applications tend to fall into two classes, the simple pointwise +transformation operators, and the more cpu intensive image analysis operations. +The simple operators usually operate upon the whole image (no mask required) +and may ignore the presence of bad pixels in the image, provided reasonable +artificial values have been provided for the bad pixels so that arithmetic +problems do not occur, and provided we keep track of the locations of the +bad pixels (by propagating the bad pixel lists), so that the bad pixel +information is available to subsequent image analysis programs. + +The image analysis operators, on the other hand, must know the locations of +the bad pixels in order to exclude them from the fit. The analysis is also +often performed only upon specified regions of the image, as indicated by some +sort of image mask. Most image analysis algorithms are fairly cpu intensive, +hence as long as we can access the bad pixel list and region mask reasonably +efficiently, we would prefer a simple interface, e.g., for every buffer of +input image data read, an associated buffer the same size and dimensionality +as the input image data buffer, containing the bad pixel or region mask flag +values. + +In general, if pixel lists are to be used with images, either IMIO must +provide direct support for pixel lists or the pixel list package must duplicate +much of the functionality of IMIO. This is because the pixel list must +be defined in terms of the physical image, whereas an applications +program accessing an image via IMIO may be operating upon some user specified +section of the image. To support applications transparent sectioning, boundary +extension, multiple input buffers, and so on, support for pixel lists must +be integrated into IMIO. + +.NH 2 +Mask Images + + These considerations lead us to make it possible for a pixel list to appear +to an application as a special type of image called a \fImask image\fR, even +though the mask may be stored as a pixel list internally, and accessed or +queried directly as a list if desired. If whenever we read a block of data +from the data image, we read an equivalent block of data from the mask image, +it is evident that whatever we come up with for reading from the mask image is +going to have to look an awful lot like IMIO. Given the complexities of image +section transformations, automatic buffer allocation strategies, and so on, +the simplest solution is to just go ahead and use IMIO to access the virtual +mask image. This leads us to the interface shown in the figure below. +These routines represent an extension to IMIO to support pixel lists. The +conventional IMIO routines, used to access the mask "pixels", are not shown. + +The mask image may be opened by name with \fIim_pmmap\fR, or an already opened +pixel mask, perhaps the result of some computation done by the applications +program, may be opened with \fIim_pmmapo\fR. Alternatively, if the mask is +stored (or will be stored in the case of a new mask) in a pixel list file +(".pl" extension), the mask may be opened with a conventional \fIimmap\fR call. +This last option is especially powerful, since it allows all image tasks to +access masks as if they were conventional images, e.g., one can DISPLAY or +IMCOPY a stored mask. + +.ks +.nf + im = im_pmmap (maskname, mode, ref_im|NULL) + im = im_pmmapo (pm, ref_im) + + imseti (im, IM_RLIO, YES|NO) + imseti (im, IM_PMDES, pm) + pm = imstati (im, IM_PMDES) + + bool = im_pmlne[123] (im[, lineno[, bandno]]) + bool = im_pmsne[123] (im, x1, x2[, y1, y2[, z1, z2]]) + bool = im_pmlnev (im, v) + bool = im_pmsnev (im, vs, ve, ndim) +.fi +.ke + +The \fImode\fR argument to \fIim_pmmap\fR specifies both the access mode for +the mask, and any standard transformations to be performed upon the mask before +i/o takes place (if an existing mask is to be read). NEW_FILE mode is used to +create a new mask; READ_ONLY to read an existing mask, and READ_WRITE to modify +an existing mask. The mode-transformation flags currently supported are +INVERT_MASK, which performs a PIX_NOT operation on the input mask, and +BOOLEAN_MASK, which converts an integer input mask to boolean. Any more +complex mask transformations or combinations must be performed explicitly +by the calling program via calls to the PMIO or PLIO routines, mapping the +resultant mask onto an image descriptor with \fIim_pmmapo\fR. + +If a reference image \fIref_im\fR is specified at open time, +then the mask image will inherit any image section, boundary extension, etc. +in effect for the reference image. Inheritance occurs when the first i/o +to the mask image takes place. The reserved names "BPM" and "EMPTY", +respectively (must be upper case), denote the bad pixel mask +for the reference image, or an empty mask the size of the reference image. +If the reference image does not have a bad pixel mask, BPM and EMPTY are +equivalent. Note that separate image descriptors are used for the data +(reference) image and any mask images. Multiple mask images may be associated +with the same reference image. + +Normal IMIO calls, e.g., \fIimgs2i\fR, are used to access the mask "pixels". +Since it is common for a mask to be empty over large regions of an image, +a set of boolean functions are provided for testing whether regions of the +mask are nonempty, allowing a program to avoid the expense of image mask i/o +and subseqent testing of the mask pixel values if not needed. +The boolean functions \fIim_pmlne\fR (line not empty) and \fIim_pmsne\fR +(section not empty) and their more general variants \fIim_pmlnev\fR and +\fIim_pmsnev\fR test whether the specified region of the mask image contains +any nonzero mask pixels. The calling sequences of these routines are patterned +after the corresponding IMIO pixel i/o routines, e.g., \fIim_pmlne2\fR is +intended for use with the \fIimgl2\fR routines, and \fIim_pmlnev\fR is +intended for use with the \fIimgnl\fR routines. + +By default, mask image i/o operates on data buffers containing arrays of +pixels, as for a conventional data image. When i/o takes place, the interface +automatically converts between pixel format and the compressed line list format +in which the mask is stored internally. An alternative format for the mask +data is \fBrange list\fR format, enabled by setting the \fIIM_RLIO\fR parameter +to YES in an \fIimseti\fR call. Range list i/o works identically to pixel i/o, +except that the "pixel arrays" returned by IMIO (or input to IMIO) are range +list structures, as defined in \fB<plset.h>\fR and discussed in section 3.3.4. + +Range list i/o at the IMIO level is fully general, i.e., the section +transformation, if any, is applied transparently to the calling program, +and the full range of IMIO i/o routines may be used. +If the data buffer is a multidimensional subraster, each line of the subraster +will be a separate range list, and the physical length in pixels of each line +of the subraster will be as for a pixel subraster. +On a read, if the length of the encoded range list exceeds the subraster +line length in pixels, and i/o error will occur. Such an i/o error cannot +occur when i/o is restricted to lines or line segments (1D buffers), +since IMIO will automatically allocate a data buffer large enough to hold +the worst case (longest) range list. Range list overflow errors are +unlikely even for subrasters, however, since the range list format is +normally much more compact than the equivalent pixel array (except for +very small subrasters or very complex masks). + +.NH 2 +Masked Image I/O (MIO) + + The mask image i/o routines discussed in the previous section provide a +fully generalized means for directly accessing a mask as an separate entity, +independent of the associated reference data image. Two separate image +descriptors are required, and two parallel but separate sets of calls to the +IMIO routines. In many applications, however, a mask is used only to specify +those regions of the data image to be analyzed or processed. We want to +access those regions of the image visible through the mask, but are not +otherwise interested in the mask itself. The \fBmasked image i/o\fR (MIO) +interface is designed for such applications. + +The MIO interface is summarized in the figure below. A named mask may be +opened on a previously opened image with the \fImio_open\fR procedure. +As for \fIim_pmopen\fR, the reserved names "BPM" and "EMPTY", respectively, +denote the bad pixel mask for the image, or an empty mask the size of the +image. If the image does not have a bad pixel mask, an empty mask will be +opened. + +The \fIflags\fR argument, if nonzero, specifies an operation be performed +upon the input mask to generate the mask to be used to access the data image. +The currently supported flags are INVERT_MASK and BOOLEAN_MASK. For example, +when the mask is a bad pixel mask, INVERT_MASK would cause MIO to access only +that portion of the image which is \fInot\fR covered by the bad pixel mask, +i.e., the "good" region of the image. BOOLEAN_MASK is used to convert an +integer mask into a boolean mask. Note that in the case of inversion of an +integer mask, the PIX_NOT operation merely complements the mask pixel values, +hence will not affect the \fIregion\fR covered by the mask. To invert an +integer mask in the region sense, use INVERT_MASK+BOOLEAN_MASK. + +.ks +.nf + mp = mio_open (maskname, flags, im) + mp = mio_openo (pm, im) + value = mio_stati (mp, param) + mio_seti (mp, param, value) + mio_setrange (mp, vs, ve, ndim) + n|EOF = mio_[gp]lseg[silrdx] (mp, ptr, mval, v, npix) + mio_close (mp) +.fi +.ke + +More general mask transformations must be carried out by the user using the +PMIO package to directly compute the desired mask, the mapping the mask onto +an image descriptor with \fImio_openo\fR. For example, given as input a bad +pixel mask and a region mask, one could compute the mask specifying all pixels +in the region mask but not in the bad pixel mask. Any general mask may be +computed in this way. + +An MIO application will not normally need to access the mask directly, but +if such access is required the mask descriptor may be obtained with a call +to \fImio_stati\fR to fetch the value of the parameter \fIP_PMDES\fR. +Similarly, the image descriptor may be queried as parameter \fIP_IMDES\fR, +and either parameter may be set with the corresponding call to \fImio_seti\fR. + +Successive calls to a get or put line segment procedure, e.g., +\fImio_glsegr\fR (get line segment real), return line segments from the data +image until all the data present in the area outlined by the mask has been +accessed, at which time EOF is returned as the function value. +Each line segment is returned along with a vector \fIv\fR specifying the +line of the image from which the segment is taken and the index of the first +pixel of the current line segment within the line, a count \fInpix\fR of the +number of pixels in the line segment, and the mask value \fImval\fR for the +current line segment (e.g., 1 for a boolean mask). Each line segment +corresponds to a region of constant nonzero value (\fImval\fR) in the mask. +Line segments are returned sequentially in storage order. + +By default, the entire region of the image visible through the mask will be +accessed. To access only a portion of the image, the \fIimio_setrange\fR +procedure may be called before performing any i/o to specify the starting and +ending vector coordinates \fIvs\fR and \fIve\fR of the region to be accessed. +Multiple calls may be made on the same MIO descriptor to access multiple +regions of the data image, or to "rewind" a given region of the image. + +.NH 2 +Mask Image Storage + + As we shall see in the discussion of the pixel list package, the pixel +list package is designed to permit a list to be stored anywhere, e.g., +in a binary file, in a database, as an array in an image header, +or merely as a temporary array in memory. When the new image structures +become available storing the masks in the image header or in a global database +will probably be the best approach, but in the meantime the simplest solution +is to store each pixel list or mask in a small binary file. This approach has +the advantage of being independent of the particular image format used (none +of which are currently capable of storing the pixel list directly in any case). + +If desired, the name of the mask file may be stored in the image header +as a simple string valued parameter. Alternatively, the mask name may be +input as a parameter when a task is run. A single mask may be associated +with several images, or several masks may be used with the same image. +The approach to be followed for a particular program is up to the programmer +or package designer. + +The bad pixel mask is a special case, since it has a well defined logical +meaning for an image, unlike the region masks which are application specific. +The most straightforward approach is to use a single boolean mask for the +bad pixel list, using the optional header keyword \fIBPM\fR to store the +mask name, which should normally be the image name plus the pixel list file +extension "\fI.pl\fR". An integer BPM could also be used, but most applications +would treat it as a boolean mask, treating any pixel with a nonzero value as +a bad pixel. + +Any additional information required to describe the bad pixels is application +specific, and may be stored in any of several ways, e.g., as a set of boolean +masks, in an integer mask, using flag bits or reserved values to describe each +pixel or region, in a separate fully populated weight image, or using the noise +function package. Most IRAF applications will probably use the BPM plus a +noise function, with the noise function being stored either as +a one-dimensional noise model or as a separate uncertainty image, transparently +to the application. The combination of a one-dimensional noise model plus a +compressed bad pixel list should provide an efficient and flexible solution +to the pixel variance problem for most applications. + +.NH 2 +Example + + Open a data image and the associated mask image, and sum the pixels within +the area indicated by the mask. + +.nf + include <pmset.h> + + task sum = t_sum +.fi + +.tp 6 +.nf + # SUM -- Sum the image pixels lying within the given mask. + + procedure t_sum() + + char image[SZ_FNAME] # input data image + char mask[SZ_FNAME] # image mask + + int npix, mval, totpix, m_flags + long v[PM_MAXDIM] + pointer im, mp, pp + real sum + + bool clgetb() + real asumr() + int mio_glsegr() + pointer immap(), mio_open() + + begin + call clgstr ("image", image, SZ_FNAME) + call clgstr ("mask", mask, SZ_FNAME) + m_flags = 0 + if (clgetb ("invert")) + m_flags = INVERT_MASK + + im = immap (image, READ_ONLY, 0) + mp = mio_open (mask, m_flags, im) + + sum = 0; totpix = 0 + while (mio_glsegr (mp, pp, mval, v, npix) != EOF) { + sum = sum + asumr (Memr[pp], npix) + totpix = totpix + npix + } + + call mio_close (mp) + call imunmap (im) + + call printf ("%d pixels, sum=%g, mean=%g\n") + call pargi (totpix) + call pargr (sum) + if (totpix > 0) + call pargr (sum / totpix) + else + call pargr (INDEF) + end +.fi + +A more complex application might use the spatial information provided by +\fIv\fR and \fInpix\fR, or the flag values provided by \fImval\fR (for an +integer mask). For example, a surface fitting routine would accumulate each +line segment into a least squares matrix, using the coordinate information +provided as well as the pixel values. + +.NH 2 +The Pixel Mask Package (PMIO) + + We have thus far discussed two quite different interfaces, i.e., the use +of IMIO to do pixel i/o to a mask mapped as a virtual mask image, and the MIO +interface, used to access the portion of a data image visible through a mask. +The next step is to define the interface used to access the mask object +directly as a \fImask\fR, independently of the use of masks for image i/o. + +.nf + pm = pm_newmask (ref_im, depth) + + pm = pm_open (bufptr|NULL) + pm = pm_create (naxes, axlen, depth) + pm = pm_newcopy (pm) + pm_close (pm) + + pm_[sg]size (pm, naxes, alxen, depth) + pm_seti (pm, param, value) + value = pm_stati (pm, param) + pm_debug (pm, outfd, maxcol, flags) + bool = pm_empty (pm) + pm_compress (pm) + pm_clear (pm) + + pm_load (pm, bufptr) + nwords = pm_save (pm, bufptr, buflen) + pm_loadf (pm, fname, title, maxch) + pm_savef (pm, fname, title, save_flags) + pm_[load|save]im (pm, imname[, save_flags]) + + ptr = pm_access (pm, v) + bool = pm_linenotempty (pm, v) + bool = pm_sectnotempty (pm, vs, ve, ndim) + pm[gp]l[lrp][sil] (pm, v, buf, b_depth, npix, rop) + + pm_[set|get]plane (pm, v) + pm_point (pm, x, y, rop) + pm_circle (pm, x, y, r, rop) + pm_box (pm, x1,y1, x2,y2, rop) + pm_line (pm, x1,y1, x2,y2, width, rop) + pm_polygon (pm, x, y, npts, rop) + + pm_rop (pm_src, vs, pm_dst, vs, vn, rop) + pm_stencil (pm_src, vs, pm_dst, vs, pm_stl, vs, vn, rop) +.fi + +There are two variants on this lowest level interface, known as PMIO (pixel +mask i/o) and PLIO (pixel list i/o). These two interfaces are equivalent +with one difference: PMIO can accept a reference image and inherit the section +transformation of the reference image, allowing the mask to be accessed in +the coordinate system of the reference image, while PLIO is a stand alone +interface, implemented independently of IMIO without any ties to IMIO. +PMIO is implemented as a thin layer upon PLIO, with ties to IMIO to access +the section transformation for the reference image. + +The PMIO interface is shown in the figure above. +With the exception of the additional routine \fIpm_newmask\fR, used to create +a new, empty mask the same size as a reference image, the PMIO routines are +identical to the corresponding PLIO routines except for the \fIpm\fR package +prefix, and the implied section transformation. Indeed, if no reference image +is specified or if the section transformation is unitary (the reference image +was opened without an image section), the two interfaces are identical. +Hence the discussion of PLIO in the next section will serve to document PMIO +as well. + +To use PMIO, merely include \fB<pmset.h>\fR rather than \fI<plset.h>\fR, +and set the reference image with a call to \fIpm_seti\fR, e.g., + + call pm_seti (pm, P_REFIM, ref_im) + +This step can be skipped if \fIpm_newmask\fR or \fIpm_newcopy\fR is used to +create a new mask, as the reference image will be inherited by the new mask. + +Programs which use PMIO to access a mask may also use the low level line, +range, and pixel list routines discussed in section 3.1 (\fBpl_rangerop\fR etc.) +on lists returned by PMIO, since PMIO will have already transformed the data +into the coordinate system of the reference image. + +In general, the PMIO interface should be used in preference to PLIO whenever +the mask to be accessed is logically associated with some data image or images. +The region description and logical region processing capabilities of PLIO are +very powerful in their own right, however, and PLIO should be used directly by +applications which do not consider the mask to be merely an overlay for a data +image. An example would be any application which operates upon a 2-dimensional +data structure other than an image (e.g., region filtering in the POE image +kernel). + +.NH +The Pixel List Package (PLIO) + + A pixel list is a way of representing an N-dimensional image matrix which +is well suited for applications where the represented image is sparse, or +consists of a moderate number of arbitrarily shaped regions. Routines are +provided for creating new lists, for writing to or reading from lists, +for storing or retrieving lists, and for performing various types of +operations upon entire lists to make new lists. The full set of routines +in the package are summarized in the figure below. + +A pixel list, like an image, has a fixed dimensionality and size which is +determined at list creation time for the lifetime of the list. New lists +are created with \fIpl_create\fR, which returns a pointer to an empty list. +The \fIdepth\fR parameter specifies the depth of the list in bits, i.e., +the number of bits per pixel, in the range 1-27. A boolean list has a depth +of 1 bit. In the current implementation the boolean mask is handled as a +degenerate case of an integer mask, i.e., an integer mask which happens to +have mask values in the range 0-1. + +An existing list is accessed by opening a descriptor with \fIpl_open\fR and +loading the list into the runtime descriptor structure, either by specifying +a non-NULL buffer pointer \fIbufptr\fR, or by calling one of the \fIpl_load\fR +functions after opening a null descriptor. + +.ks +.nf + pl = pl_open (bufptr|NULL) + pl = pl_create (naxes, axlen, depth) + pl = pl_newcopy (pl) + pl_close (pl) + + pl_[sg]size (pl, naxes, axlen, depth) + pl_seti (pl, param, value) + value = pl_stati (pl, param) + pl_debug (pl, outfd, maxcol, flags) + bool = pl_empty (pl) + pl_compress (pl) + pl_clear (pl) + + pl_load (pl, bufptr) + nwords = pl_save (pl, bufptr, buflen) + pl_loadf (pl, fname, title, maxch) + pl_savef (pl, fname, title, save_flags) + pl_[load|save]im (pl, imname[, save_flags]) + + ptr = pl_access (pl, v) + bool = pl_linenotempty (pl, v) + bool = pl_sectnotempty (pl, vs, ve, ndim) + pl[gp]l[lrp][sil] (pl, v, buf, b_depth, npix, rop) + + pl_[set|get]plane (pl, v) + pl_point (pl, x, y, rop) + pl_circle (pl, x, y, r, rop) + pl_box (pl, x1,y1, x2,y2, rop) + pl_line (pl, x1,y1, x2,y2, width, rop) + pl_polygon (pl, x, y, npts, rop) + + pl_rop (pl_src, vs, pl_dst, vs, vn, rop) + pl_stencil (pl_src, vs, pl_dst, vs, pl_stl, vs, vn, rop) +.fi +.ke + +Pixel lists are stored externally as opaque binary byte arrays. +The function \fIpl_save\fR will encode a pixel list as a byte array and store +it in the indicated buffer, resizing the buffer if necessary. +If \fIbufptr\fR is NULL a new buffer will be allocated, overwriting the NULL. +The \fIpl_load\fR function performs the inverse function. +The \fIf\fR suffixed functions are provided for convenience when storing +lists in small binary files. The \fIim\fR suffixed functions create masks +out of actual data images, and vice versa. In the most general case, a list +is encoded into an array in memory and then stored away by the applications +wherever they wish, e.g., as an array parameter in an image header when the +new image structures become available. + +Pixel list i/o is provided via the \fIpl[gp]l[lrp][sil]\fR family of functions, +which read, write, or edit (via the \fIrop\fR) lines or line segments of masks. +The naming convention is as follows: + +.ks +.nf + pl package prefix + [gp] get or put + l line segment + [lrp] as a line list, range list, or pixel array + [sil] in an array of type short, int, or long +.fi +.ke + +For example, \fIplglps\fR would get a line from a mask image as a fully +populated array of type short. For maximum efficiency, since this is a low +level interface, the data is read from or copied into a user allocated buffer, +rather than having the pixel list package control the buffer. + +The functions \fIplgll[sil]\fR return the packed line list for the indicated +line or line segment. This is the copy-out form of access with the least +overhead, but requires that the application have knowledge of the internal +line list format. + +Alternatively, if it is only desired to read from a list, accessing the list +in the internal format, the internal list for an image line may be directly +accessed by pointer with the \fIpl_access\fR function. This is the most +efficient form of access. The variant \fIpl_linenotempty\fR is similar except +that the NULL pointer is returned if the indicated line of the list is empty, +providing an efficient and convenient way to perform the empty test on mask +image lines. + +The functions \fIplglr[sil]\fR are similar to the get line list form of access, +but instead of returning the encoded list-list in the internal format, +it returns a simple array of ranges of absolute pixel indices and associated +mask values. This is the recommended way of accessing the mask as a list +structured object, since it does not require knowledge of the internal packed +line list format. For example, to print line \fIv\fR of the mask on descriptor +\fIpl\fR as a series of range lists: + +.ks +.nf + int buf[3,1024], n, i, plglri() + + n = plglri (pl, v, buf, 0, axlen[1], 0) + do i = 1, n { + call printf ("range at %d, %d pixels, mask value = %o\n") + call pargi (buf[1,i]); call pargi (buf[2,i]) + call pargi (buf[3,i]) + } +.fi +.ke + +These routines require that the depth in bits of the output line or range +list or pixel array be specified. This is necessary to avoid generating +numbers the size of the machine integer when inverting a mask (PIX_NOT), +e.g., if the mask depth is 8 bits, the complement of a 0 pixel should be 377, +not 37777777777. The depth argument may also be used to convert an integer +mask to a boolean mask, or vice versa (using the PIX_VALUE field of the +rasterop discussed in the next section). If \fIb_value\fR is zero, clipping +of the output values is disabled. This would be appropriate, for example, +when simply reading from a mask without modifying the pixel values. + +New pixel lists may be created by having the application prepare the packed +line lists externally, inserting them directly into the pixel list structure +with a \fIput\fR routine. This is generally inadvisable, however, because +the packed line list format is considered internal to the PLIO package. +A better alternative is to input the mask data as a populated array or +as a range list, letting the PL package manage the internal line list. + +A more convenient approach to creating or modifying masks for most applications +is to define the mask by specifying a series of include and exclude standard +region types (circles, boxes, lines, points, or polygons), +using the block of routines beginning with \fIpl_setplane\fR in the figure. +Note that these are two dimensional +operators; they are provided for convenience even though the pixel list +package can support images of any dimension (if the image has three or more +dimensions \fIpl_setplane\fR may be used to specify the plane to be operated +upon). The most general routine is \fIpl_polygon\fR, which may be used to +operate upon the pixels in the interior of any general polygon. All of the +region drawing operators will permit regions to extend beyond the boundary +of the mask, clipping as necessary at the boundary. + +.NH 2 +Pixel, Line, and Range List Routines + + Most of the N dimensional region or mask oriented PMIO and PLIO routines +eventually result in calls to the low level pixel, line, and range rasterop +routines and format conversion routines shown in the figure below. These +routines form the functional core of the PLIO package and will often be +responsible for most of the execution time of routines which use PLIO. + +There are two main classes of routines. The \fIpl_pixrop\fR, \fIpl_linerop\fR, +and \fIpl_rangerop\fR routines perform the general raster operation on pixel +arrays, line lists, and range lists. The \fIpl_linestencil\fR routine performs +the stencil rasterop operation upon line lists; currently only a list list +version is available since this is a rarely used routine. Lastly, a set of +six routines are provided for converting between any two of the three formats, +e.g., line list to range list or pixel array and vice versa, omitting the +like-to-like conversions. For example, \fIpl_p2ri\fR would convert a pixel +array to a range list, both of type integer. + +.ks +.nf + pl_linerop (ll_src, xs, src_maxval, + ll_dst, ds, dst_maxval, ll_out, npix, rop) + pl_linestencil (ll_src, xs, src_maxval, ll_dst, ds, dst_maxval, + ll_stn, xs, ll_out, npix, rop) + + pl_pixrop[sil] (px_src, xs, src_maxval, + px_dst, ds, dst_maxval, npix, rop) + pl_rangerop[sil] (rl_src, xs, src_maxval, + rl_dst, ds, dst_maxval, rl_out, npix, rop) + + n = pl_[lrp]2[lrp][sil] (op_src, xs, op_dst, npix) +.fi +.ke + +Note that these low level routines +specify the mask depth as a maximum pixel value, rather than taking the depth +in bits as the high level PMIO and PLIO routines do, and that there are no +\fI"pm_"\fR versions of these routines - the one set of routines may be used +with both PLIO and PMIO. + +.NH 2 +Rasterops + + The argument \fIrop\fR in the circle, box, and other routines discussed +in the previous sections is called a \fBrasterop\fR, and specifies the bitwise +operation to be performed to generate the destination operand. Much of the +generality and conciseness of the pixel list package is due to the rasterop +abstraction, which is patterned after a similar construct used by the Sun +Microsystems \fISunview\fR interface to specify operations upon \fIpixrects\fR, +which are logically similar to PLIO masks. + +The rasterop defines the operation to be performed to generate the destination +mask, in terms of bitwise boolean operations performed upon the input source +and destination masks. Rasterops are constructed via a series of bitwise +\fIand\fR and \fIor\fR operations, using the following macro defines: + +.ks +.nf + PIX_SRC specifies the source mask + PIX_DST specifies the destination mask + PIX_NOT(op) inverts the operand mask + PIX_VALUE(value) specifies the bitplanes to be set +.fi +.ke + +Examples of some of the possible operations (out of a total of 16 possible +operations) are shown below. This table is reproduced from the SunView +Pixrect Reference Manual. + +.ks +.nf + \fIRasterop\fR \fIDescription\fR + + PIX_SRC copy source to destination + PIX_DST no-op + PIX_SRC | PIX_DST paint (OR source to destination) + PIX_SRC & PIX_DST mask (AND of source and destination) + PIX_NOT(PIX_SRC)&PIX_DST erase (AND destination with negation + of source) + PIX_NOT(PIX_DST) invert area (negate the existing + values) + PIX_SRC ^ PIX_DST inverting paint (XOR of source and + destination) +.fi +.ke + +Here, the |&^ denote the SPP \fIor\fR, \fIand\fR, and \fIxor\fR intrinsic +functions, which must be used to construct actual rasterop expressions in SPP, +e.g.: + + PIX_NOT(PIX_SRC) | PIX_DST | PIX_VALUE(v) + +would actually be written as + + or (PIX_NOT(PIX_SRC), PIX_DST) + PIX_VALUE(v) + +The following additional macros are defined to deal with the more common +cases of setting or clearing a region. + +.ks +.nf + PIX_SET (PIX_SRC | PIX_NOT(PIX_SRC)) + PIX_CLR (PIX_SRC & PIX_NOT(PIX_SRC)) +.fi +.ke + +As a simple example, consider the case of specifying a region mask as a series +of include and exclude circles and boxes. This is trivial for a boolean mask: +an include circle or box is specified by the rasterop PIX_SET, and an exclude +by PIX_CLR. In the equivalent operation upon an integer mask this would cause +any mask values which had already been set to be replaced, hence it might be +desirable to use a PIX_SRC|PIX_DST rasterop instead, to OR the bits of the new +flag values into those of any flag values already set. Similarly, when using +\fIpl_ltop\fR to unpack a line list into a pixel array, the PIX_SRC|PIX_DST +rasterop might be specified to OR the mask segment into an existing pixel +array. + +General bitwise boolean operations upon masks are provided by the \fIpl_rop\fR +and \fIpl_stencil\fR operators, which operate upon entire masks or rectangular +subregions of masks. The \fIpl_rop\fR operator combines the source and +destination masks to produce a new mask; \fIpl_stencil\fR performs the same +operation, but only in the regions specified by the stencil mask, +which must be a boolean mask. The input mask may be NULL (depending upon +the rasterop specified), or the source and destination masks may be the same. + +The equivalent operators for line lists, range lists, and pixel arrays are +the \fIpl_S2D\fR family of routines, where \fIS=D=[lrp]\fR for a line list, +range list, or pixel array rop. The routine \fIpl_linestencil\fR implements +the stencil operation for a line list. + +As noted above, when operating upon integer masks (\fIdepth\fR > 1), the +PIX_VALUE macro is used to specify the flag value for the indicated region. +For example, the following rasterop would set all the pixels in a region to +the same value: + + PIX_VALUE(value) + +to OR in the new value instead of replacing any existing flag values: + + PIX_VALUE(value) | PIX_DST + +If a boolean mask is to be written to an integer mask, PIX_VALUE specifies +the flag value to be used for the regions set to 1 in the input boolean mask. +For example, one might wish to combine a set of 8 boolean masks to form a +single 8 bit deep integer mask, with each bit in the integer mask corresponding +to one of the input boolean masks (001 = mask 1, 002 = mask 2, 040 = mask 3, +etc.). This could be done using the rasterop shown above, incrementing +PIX_VALUE in each operation to specify the bitplane to be set. + +.NH 3 +Rasterop Expression Evaluation + + As mentioned above, there are sixteen possible ways to combine the source +and destination masks subject to the four possible boolean operations +(\fIand\fR, \fIor\fR, \fIxor\fR, and \fInot\fR). +More precisely, although numerous bitwise expressions can be constructed, many +of these are equivalent, and there are only sixteen fundamental operations. +These are summarized in the following table. + +.nf + Operation Opcode + + PIX_CLR 00 + PIX_SET 17 + + PIX_SRC 14 + PIX_DST 12 + + PIX_NOT(PIX_SRC) 03 + PIX_NOT(PIX_DST) 05 + + PIX_SRC & PIX_DST 10 + PIX_SRC | PIX_DST 16 + PIX_SRC ^ PIX_DST 06 + + PIX_SRC & PIX_NOT(PIX_DST) 04 + PIX_SRC | PIX_NOT(PIX_DST) 15 + PIX_NOT(PIX_SRC) & PIX_DST 02 + PIX_NOT(PIX_SRC) | PIX_DST 13 + + PIX_NOT (PIX_SRC & PIX_DST) 07 + PIX_NOT (PIX_SRC | PIX_DST) 01 + PIX_NOT (PIX_SRC ^ PIX_DST) 11 +.fi + +As an example of the redundancy of arbitrary rasterop expressions, +compare the following with the equivalent expressions (same opcode) +in the table above. + +.ks +.nf + PIX_NOT(PIX_SRC) & PIX_NOT(PIX_DST) 01 + PIX_NOT(PIX_SRC) ^ PIX_NOT(PIX_DST) 06 + PIX_NOT(PIX_SRC) | PIX_NOT(PIX_DST) 07 + PIX_NOT(PIX_SRC) ^ PIX_DST 11 + PIX_SRC ^ PIX_NOT(PIX_DST) 11 +.fi +.ke + +Any number of additional logically redundant expressions may be constructed. +The programmer should not worry about simplifying logical expressions, +but should choose instead whatever expression is clearest for their particular +application, letting the interface handle expression optimization internally. + +Of the sixteen possible fundamental operations, there are four trivial +operations (\fIclr\fR, \fIset\fR, \fIsrc\fR, \fIdst\fR), +seven composite operations, and four primary operations, namely, +\fIand\fR, \fIor\fR, \fIxor\fR, and \fInot\fR (two cases of the latter). +The composite operations are all implementable as two primary +operations in sequence. PIX_NOT is implemented by actual inversion of the +list rather than as a mode flag, to avoid complications when the list is read. + +.NH 3 +Rasterop Encoding + + The rasterop argument specifies the bitwise boolean operation to be +performed, and optionally the pixel value to be used (in the case of an +integer mask). Both are specified as a single integer value, packed as +shown in the figure below. + +.ks +.nf + +--+-------------+--------+ + |32|31 5|4 1| + +--+-------------+--------+ + | | pixel value | opcode | + +--+----------------------+ +.fi +.ke + +The following is an example of a typical rasterop (note that since the pixel +value field has a reserved range of bits which is zero prior to expression +evaluation, the "+" operator is equivalent to the \fIor\fR intrinsic function). + + or(PIX_SRC, PIX_NOT(PIX_DST)) + PIX_VALUE(pix_value) + +Note that the width of the pixel value field in the rasterop constrains the +effective mask depth to be 27 bits or less, if full generality is desired in +rasterop operations. Masks of up to 31 bits (the minimum unsigned precision +of a \fIlong\fR) can be stored and accessed, but rasterops using PIX_VALUE +are limited to 27 bits. + +.NH 2 +Pixel List Data Structures + + A pixel list consists of an array of pointers to the \fIline lists\fR +forming the mask. There is one pointer for each image line; if the pointer +is NULL, no mask values are set on the associated image line. N-dimensional +images are easily handled by an N-1 dimensional array of line pointers. + +Each line list consists of a series of offsets and mask pixel values +(the pixel values are normally omitted for a boolean mask). +The offsets specify the number of pixels for which the mask has the same value. +This line list format has the following two significant advantages over the +alternative technique of specifying a list of ranges using absolute pixel +coordinates: +.ls +.ls [1] +A higher degree of data compression is possible. If absolute pixel +coordinates are used in the list, the list must be an array of 32 bit +integer values in order to avoid a builtin limit on the size of the image +which can be represented. By using offsets, list elements as small as +one byte are possible. +.le +.ls [2] +A list composed of offsets is invariant with respect to translation. +For example, when extracting a subraster of an image, one can extract the +corresponding segment of each line list and perhaps edit the first element, +and the remainder of the list may be used without change. +.le +.le + +When describing regular regions such as boxes it will often be the case that +successive lines of the mask are equivalent, in which case multiple line list +pointers may point to the same line list. Hence, the line lists will provide +good compression of regular objects in any two dimensional plane of the mask. +This technique can be extended to higher dimensions if desirable, without +affecting the line list data structures visible to an application. + +.NH 3 +Line List Encoding + + A good compromise between storage efficiency and efficiency of runtime +access, while keeping things simple, is achieved if we maintain the compressed +line lists as variable length arrays of type short integer (16 bits per list +element), regardless of the mask depth. A line list consists of a series of +simple \fIinstructions\fR which are executed in sequence to reconstruct a line +of the mask. Each 16 bit instruction consists of the sign bit (not used at +present), a three bit \fIopcode\fR, and twelve bits of data, i.e.: + +.ks +.nf + +--+-----------+-----------------------------+ + |16|15 13|12 1| + +--+-----------+-----------------------------+ + | | opcode | data | + +--+-----------------------------------------+ +.fi +.ke + +The significance of the data depends upon the instruction. The instructions +currently implemented are summarized in the table below. + +.ks +.nf + Instruction Opcode Description + + ZN 00 Output N zeros + HN 04 Output N high values + PN 05 Output N-1 zeros plus one high value + SH 01 Set high value, absolute + IH,DH 02,03 Increment or decrement high value + IS,DS 06,07 Like IH-DH, plus output one high value +.fi +.ke + +In order to reconstruct a mask line, the application executing these +instructions is required to keep track of two values, +the \fIcurrent high value\fR and the \fIcurrent position\fR in the output line. +The detailed operation of each instruction is as follows: +.ls 4 +.ls 8 ZN +Zero the next N (=\fIdata\fR) output pixels. +.le +.ls HN +Set the next N output pixels to the current high value. +.le +.ls PN +Zero the next N-1 output pixels, and set pixel N to the current high value. +.le +.ls SH +Set the high value (absolute rather than incremental), taking the high 15 bits +from the next word in the instruction stream, and the low 12 bits from the +current data value. +.le +.ls IH,DH +Increment (IH) or decrement (DH) the current high value by the \fIdata\fR +value. The current position is not affected. +.le +.ls IS,DS +Increment (IS) or decrement (DS) the current high value by the \fIdata\fR +value, and \fIstep\fR, i.e., output one high value. +.le +.le + +The high value is assumed to be set to 1 at the beginning of a line, hence +the IH,DH and IS,DS instructions are not normally needed for boolean masks. +If the length of a line segment of constant value or the difference between +two successive high values exceeds 4096 (12 bits), then multiple instructions +are required to describe the segment or intensity change. + +The performance of this encoding is very good for typical masks consisting +of isolated high or low values or extended regions at the same level. +The worst case performance occurs when successive pixels have different values. +Even in this case the encoding will only require one word (16 bits) per mask +pixel, provided either the delta intensity change between pixels is usually +less than 12 bits, or the mask represents a zero floored step function of +constant height. The worst case cannot exceed npix*2 words provided the mask +depth is 24 bits or less. + +.NH 3 +Example: Line List Encoding + + As a simple example, consider the following line of a boolean mask. +The set pixels are 1, 4, 8 through 11, and so on, shown as \fIindex list\fR +in the figure. The corresponding \fIoffset list\fR (line list encoding) +is also shown. Note that both encodings require the same amount of space, +assuming 16 bits per list element in both cases; the index list would require +twice as much space if 32 bit list elements were used. + +.ks +.nf + Index list: 1, 4, 8-11, 15, 23-39 7 words + Offset list: P1 P3 Z3 H4 P4 Z7 H17 7 words + + Inverted I-L: 2-3, 5-7, 12-14, 16-22 8 words + Inverted O-L: Z1 H2 Z1 H3 Z4 H3 Z1 H7 8 words +.fi +.ke + +The bottom half of the figure shows the encodings for the inverted lists, +i.e., the lists which would be produced by a PIX_NOT rasterop operation. +Since both encodings reflect only the points in a line where level changes +occur, the information content and list size of the normal and inverted +lists are comparable. The encoding for an integer mask would be equivalent +except for the addition of occasional SH or SL instructions to set the high +value. + +.NH 3 +Line List Structure + + The full line list structure consists of a header describing the line +list entry in the PLIO descriptor, plus the LL encoding of the line, as +illustrated below. This information is internal to the PLIO package and +should not be used in applications code. [The LL header was generalized +in Aug2000 to permit larger masks; see plio.h] + +.ks +.nf + define LL_START 4 + struct linelist { + short nref # number of lines pointing here + short blen # length of buffer containing list + short len # encoded linelist length, words + short ll[] # encoded pixel data + } +.fi +.ke + +The linelist encoding includes any trailing zeros, i.e., executing of the +encoded instructions will regenerate the entire mask line. + +.NH 3 +Range List Structure + + The range list structure provides applications programs with a list +representation of a mask, for cases where it would be inefficient or +inconvenient to access the mask as a pixel array. Range lists are not +used to store masks in external storage, hence data compression is not an +issue, nor is machine independence. + +.ks +.nf + rtype = short|int|long + struct rangelist { + rtype x # x coordinate of first pixel + rtype n # number of pixels in range + rtype v # pixel value + } + + int rl[3,ARB] # typical range list array decl +.fi +.ke + +The range list structure is defined in <plset.h>, e.g. (refer to the actual +file for more reliable documentation for these definitions): + +.ks +.nf + RL_FIRST # first data range entry in list + RL_LENELEM # size of each element of list (i.e., 3) + RL_MAXLEN # maximum range list length (arg=pl) + + RL_LEN # physical length of range list (RL_LEN(rl)) + RL_AXLEN # length of mask image line (RL_AXLEN(rl)) + RLI_LEN # RL_LEN for rl = ptr to int + RLI_AXLEN # RL_AXLEN " " " + RLS_LEN # RL_LEN for rl = ptr to int + RLS_AXLEN # RL_AXLEN " " " + + RL_X # use as RL_X(rl,i), rl = range list array + RL_N # Npix field of range list array element + RL_V # Value field of range list array element + + RL_XOFF # offset of xstart field + RL_NOFF # offset of npix field + RL_VOFF # offset of value field +.fi +.ke + +The range list is represented as a simple two dimensional integer or +short integer array. The first line of the two dimensional array is +used as the \fBrange list header\fR, and is used to store the \fIlen\fR +and \fIaxlen\fR parameters describing the encoded mask line. Each +subsequent entry defines a range \fInpix\fR of mask image pixels, +starting at pixel \fIx\fR (absolute pixel coordinates), all of which +have the value \fIvalue\fR. Only nonzero ranges are stored. +Note that the \fIlen\fR field defines the entire length of the structure, +including the header range and data ranges. + +.NH 3 +Example: A Small Mask + + A complete example of a small mask (75 columns by 40 lines) is shown below. +This mask and the sample output were prepared by the PLIO debug interpreter, +file \fIzzdebug.x\fR in the PLIO source directory. + +.nf +40 .1111111..............................................................22222 +39 .1111111..............................................................22222 +38 .1111111...............................................................2222 +37 .1111111...............................................................2222 +36 .1111111............................................................4...... +35 .1111111.....................11111111111111111111111111...........4444..... +34 .1111111.....................11111111111111111111111111........44444444.... +33 .1111111......................1111111111111111111111111......44444444...... +32 .1111111......................1111111111111111111111111...44444444......... +31 .1111111......................1111111111111111111111111.44444444........... +30 .1111111...........4..........1111111111111111111111115444444.............. +29 .1111111...........4..........11111111111111111111155554444................ +28 .1111111...........4..........111111111111111111155555544.................. +27 .1111111...........4..........1111111111111111555555551.................... +26 .1111111.....................11111111111111155555555111.................... +25 .1111111.....................11111111111115555555111111.................... +24 ............................1111111111155444444.1111111.................... +23 ...........................111111111155544444....111111.................... +22 ..............1...........1111111155555444........11111.................... +21 ........................1111111155555554..........11111.................... +20 ........................111111555555511...........11111.................... +19 ........................111555555551111...........11111.................... +18 ........................155555555111111...........11111.................... +17 ......................445555551111111111.........111111.................... +16 ....................444455551111111111111.......1111111.................... +15 ..................4444445111111111111111111111111111111.................... +14 ...............44444444.1111111111111111111111111111111.................... +13 .............44444444...................................................... +12 ..........44444444......................................................... +11 ........44444444........................................................... +10 .........4444........................22222................................. + 9 ..........4.........................2222222..............22222............. + 8 ....................................2222222.............2222222............ + 7 ....................................2222222.............2222222............ + 6 .....................................22222..............2222222............ + 5 11111111111111111111.....................................22222............. + 4 11111111111111111111....................................................... + 3 11111111111111111111....................................................... + 2 11111111111111111111....................................................... + 1 11111111111111111111....................................................... + 123456789012345678901234567890123456789012345678901234567890123456789012345 + 1 2 3 4 5 6 7 +.fi + +This first figure shows the mask itself, output graphically as a character +matrix. This is an integer mask wherein the integer value of each pixel is +the ASCII value of the character shown. The mask was created by \fIor\fR-in +a number of regions together, using a different mask value for each region. +The result in areas where the regions intersect is a new mask pixel value. + +The figure below shows the internal data structures used to represent the +previous mask. Both the line list and range list representations of the +mask are shown. The size of the packed line list is 582 words, 189 of which +are free (no longer used due to updates), hence the packed line list size +would be 393 words following a call to \fIpl_compress\fR to compress the mask. + +.nf + Mask 1EECD naxes=2 [75,40] maxval=177 plane=[75,40] + max buffered line size 1024, max actual line size 16 + 40 lines total, 40 are nonempty, mask is nonempty + llbp=42AF5, len=1190, op=583, free=189, nupdates=35 + + Index at 1EFF1 containing 40 lines: + 4 4 4 4 17 26 35 35 166 177 187 + 194 201 208 218 228 241 254 266 554 292 568 + 319 333 347 360 492 507 523 539 423 435 447 + 459 471 483 148 148 157 157 + + Line list containing 40 lines: + [1:4] IH48(49) H20 Z55 (75,49) + [5] IH48(49) H20 IH1(50) Z37 H5 Z13 (75,50) + [6] IH49(50) Z37 H5 Z14 H7 Z12 (75,50) + [7:8] IH49(50) Z36 H7 Z13 H7 Z12 (75,50) + [9] IH51(52) P11 DH2(50) Z25 H7 Z14 H5 Z13 (75,50) + [10] IH51(52) Z9 H4 DH2(50) Z24 H5 Z33 (75,50) + [11] IH51(52) Z8 H8 Z59 (75,52) + [12] IH51(52) Z10 H8 Z57 (75,52) + [13] IH51(52) Z13 H8 Z54 (75,52) + [14] IH51(52) Z15 H8 DH3(49) Z1 H31 Z20 (75,49) + [15] IH51(52) Z18 H6 IS1(53) DH4(49) H30 Z20 (75,49) + [16] IH51(52) Z20 H4 IH1(53) H4 DH4(49) H13 Z7 H7 Z20 (75,49) + [17] IH51(52) Z22 H2 IH1(53) H6 DH4(49) H10 Z9 H6 Z20 (75,49) + [18] IH48(49) P25 IH4(53) H8 DH4(49) H6 Z11 H5 Z20 (75,49) + [19] IH48(49) Z24 H3 IH4(53) H8 DH4(49) H4 Z11 H5 Z20 (75,49) + [20] IH48(49) Z24 H6 IH4(53) H7 DH4(49) H2 Z11 H5 Z20 (75,49) + [21] IH48(49) Z24 H8 IH4(53) H7 DS1(52) DH3(49) Z10 H5 Z20 + (75,49) + [22] IH48(49) P15 Z11 H8 IH4(53) H5 DH1(52) H3 DH3(49) Z8 H5 + Z20 (75,49) + [23] IH48(49) Z27 H10 IH4(53) H3 DH1(52) H5 DH3(49) Z4 H6 Z20 + (75,49) + [24] IH48(49) Z28 H11 IH4(53) H2 DH1(52) H6 DH3(49) Z1 H7 Z20 + (75,49) + [25] IH48(49) Z1 H7 Z21 H13 IH4(53) H7 DH4(49) H6 Z20 (75,49) + [26] IH48(49) Z1 H7 Z21 H15 IH4(53) H8 DH4(49) H3 Z20 (75,49) + [27] IH48(49) Z1 H7 IH3(52) P12 DH3(49) Z10 H16 IH4(53) H8 + DS4(49) Z20 (75,49) + [28] IH48(49) Z1 H7 IH3(52) P12 DH3(49) Z10 H19 IH4(53) H6 + DH1(52) H2 Z18 (75,52) + [29] IH48(49) Z1 H7 IH3(52) P12 DH3(49) Z10 H21 IH4(53) H4 + DH1(52) H4 Z16 (75,52) + [30] IH48(49) Z1 H7 IH3(52) P12 DH3(49) Z10 H24 IS4(53) + DH1(52) H6 Z14 (75,52) + [31] IH48(49) Z1 H7 Z22 H25 IH3(52) Z1 H8 Z11 (75,52) + [32] IH48(49) Z1 H7 Z22 H25 IH3(52) Z3 H8 Z9 (75,52) + [33] IH48(49) Z1 H7 Z22 H25 IH3(52) Z6 H8 Z6 (75,52) + [34] IH48(49) Z1 H7 Z21 H26 IH3(52) Z8 H8 Z4 (75,52) + [35] IH48(49) Z1 H7 Z21 H26 IH3(52) Z11 H4 Z5 (75,52) + [36] IH48(49) Z1 H7 IH3(52) P61 Z6 (75,52) + [37:38] IH48(49) Z1 H7 IH1(50) Z63 H4 (75,50) + [39:40] IH48(49) Z1 H7 IH1(50) Z62 H5 (75,50) + + Line list containing 40 lines: + [1:4] 1-20(49) + [5] 1-20(49) 58-62(50) + [6] 38-42(50) 57-63(50) + [7:8] 37-43(50) 57-63(50) + [9] 11(52) 37-43(50) 58-62(50) + [10] 10-13(52) 38-42(50) + [11] 9-16(52) + [12] 11-18(52) + [13] 14-21(52) + [14] 16-23(52) 25-55(49) + [15] 19-24(52) 25(53) 26-55(49) + [16] 21-24(52) 25-28(53) 29-41(49) 49-55(49) + [17] 23-24(52) 25-30(53) 31-40(49) 50-55(49) + [18] 25(49) 26-33(53) 34-39(49) 51-55(49) + [19] 25-27(49) 28-35(53) 36-39(49) 51-55(49) + [20] 25-30(49) 31-37(53) 38-39(49) 51-55(49) + [21] 25-32(49) 33-39(53) 40(52) 51-55(49) + [22] 15(49) 27-34(49) 35-39(53) 40-42(52) 51-55(49) + [23] 28-37(49) 38-40(53) 41-45(52) 50-55(49) + [24] 29-39(49) 40-41(53) 42-47(52) 49-55(49) + [25] 2-8(49) 30-42(49) 43-49(53) 50-55(49) + [26] 2-8(49) 30-44(49) 45-52(53) 53-55(49) + [27] 2-8(49) 20(52) 31-46(49) 47-54(53) 55(49) + [28] 2-8(49) 20(52) 31-49(49) 50-55(53) 56-57(52) + [29] 2-8(49) 20(52) 31-51(49) 52-55(53) 56-59(52) + [30] 2-8(49) 20(52) 31-54(49) 55(53) 56-61(52) + [31] 2-8(49) 31-55(49) 57-64(52) + [32] 2-8(49) 31-55(49) 59-66(52) + [33] 2-8(49) 31-55(49) 62-69(52) + [34] 2-8(49) 30-55(49) 64-71(52) + [35] 2-8(49) 30-55(49) 67-70(52) + [36] 2-8(49) 69(52) + [37:38] 2-8(49) 72-75(50) + [39:40] 2-8(49) 71-75(50) +.fi + +The line list and range list tables shown consist of two columns, the first +listing the range of mask lines pointing to the line or range list shown to +the right (a sequence of identical mask lines will point to the same encoded +line list). Each instruction which changes the mask pixel value is followed +by the new current mask value in parenthesis. Zero ranges are omitted in +the range list format. The "pl_circle" regions appear as ellipses since +a printed character does not have a unit aspect ratio. + +.NH 3 +Pixel List Descriptor + + For runtime access to a mask we require, for an N dimensional mask, an +N-1 dimensional array of line list pointers, plus the line lists themselves. +Multiple line list pointers may point to the same encoded line list. +All line pointers are valid at all times, i.e., NULL pointers are not +permitted, even for empty mask lines. Initially, all line pointers will +point to the same entry, the encoded line list representation of an empty +line, i.e., a line of zeros (i.e., the single instruction ZN where N=axlen[1]). + +.ks +.nf + struct pldes { + int pl_magic # magic / version no. + int pl_private1 # used by PMIO (ref_im) + int pl_private2 # used by PMIO (mapxy flag) + int pl_maxline # max encoded line lentgh + int pl_maxval # mask depth as max pixel value + int pl_naxes # number of axes + int pl_axlen[7] # axis lengths + int pl_plane[7] # current plane for pl_setplane + int pl_llbp # line list bufptr + int pl_llop # next location in llbuf + int pl_lllen # current llbuf length + int pl_llfree # amount of free space in list + int pl_llnupdates # line list has been modified + int pl_llinc # llbuf increment on overflow + int pl_nlp # number of line pointers + int pl_lp[] # array of line pointers + } +.fi +.ke + +The main descriptor, which is a dynamically allocated data structure, is a +fixed size descriptor, the size of which depends upon the dimensionality and +size of the mask. A single additional dynamically allocated buffer of type +\fIshort\fR is used to store the encoded line lists. The size of this buffer +may vary at runtime as the mask is edited. New line lists, or edited line +lists which increase in size, are inserted at the end of the buffer. +As existing line lists are freed a count of the amount of free space is +kept in \fIpl_llfree\fR. If the percent of free space reaches a predetermined +level garbage collection is possible by copying the list, otherwise the line +list buffer is reallocated to increase its size. The line pointers \fIpl_lp\fR +are actually offsets into \fIllbuf\fR, rather than true pointers. + +.NH 3 +External Storage Format + + A mask is stored externally as a variable length array of 32 bit MII +integers (the stored mask header) followed by two variable length arrays of +16 bit MII integers, packed in the following format: + +.ks +.nf + struct pl_extern { + int ple_magic # magic / version no. + int ple_naxes # mask dimensionality + int ple_axlen[7] # length of each axis + int ple_llop # output pointer into llbuf + int ple_lllen # llbuf length, words + int ple_nlp # number of line pointers (lines) + int ple_nlpx # length of compressed index + int ple_exlen # length of full pl_extern struct + int ple_flags # flag bits + int ple_maxline # saved pl_maxline + int ple_maxval # saved pl_maxval + short ple_pkindex[] # packed line list index array + short ple_llbuf[] # line list buffer + } +.fi +.ke + +The \fIpl_compress\fR function is applied before a mask is encoded +into the external storage format, to eliminate the unused space in the line +list buffer which occurs during dynamic updates to the runtime list structure. +The line list index, containing one integer entry for each line in the mask +in the runtime format, is compressed using \fIpl_p2li\fR, storing in the +external representation the compressed array encoded as a line list in +\fIple_pkindex\fR. This is especially important for large masks, as otherwise +the index array could be by far the biggest contributor to the size of the +mask when encoded into its external format. + +No format conversions are required other than decoding the compressed line list +index and possibly byte swapping, hence accessing a stored list is very fast. +Further data compression is possible when packing the list for storage, but it +is not clear if this is justified. diff --git a/sys/plio/README b/sys/plio/README new file mode 100644 index 00000000..440bf528 --- /dev/null +++ b/sys/plio/README @@ -0,0 +1,288 @@ +PMIO -- The Pixel Mask I/O package (PLIO for image masks). +PLIO -- The Pixel List I/O package (no ties to IMIO) + + A PIXEL LIST is a compressed, region oriented data structure used to store +an image matrix. The pixel list package is used to create, manage, and access +this data structure. Although the PLIO package can stand alone and is useful +in its own right, one of the main uses of the pixel list package is in the IMIO +interface, which can access a pixel list as if it were a MASK IMAGE. +See PLIO.hlp for further information on the PLIO package and image masks. + +The pixel list package itself does not support any fancy image coordinate +transformations. If an image has an associated pixel mask, the pixel mask +refers to the physical image matrix. An application written at the IMIO level +where an image section transformation may be defined for an image should +normally use the PMIO (pixel mask) package in preference to PLIO. PMIO is +equivalent to PLIO, except that coordinates are input in image section +coordinates, and a reference image is used to map such coordinates onto the +physical image matrix. + + +1. IMIO Mask Image Interface + + im = im_pmmap (maskname, mode, ref_im|NULL) + im = im_pmmapo (pm, ref_im) + + imseti (im, IM_RLIO, YES|NO) # enable range list i/o + imseti (im, IM_PMDES, pm) # inquire PM descriptor + pm = imstati (im, IM_PMDES) + + bool = im_pmlne[123] (im[, lineno[, bandno]]) + bool = im_pmsne[123] (im, x1, x2[, y1, y2[, z1, z2]]) + bool = im_pmlnev (im, v) + bool = im_pmsnev (im, vs, ve, ndim) + + mp = mio_open (maskname, flags, im) # Masked Image I/O + mp = mio_openo (pm, im) + value = mio_stati (mp, param) + mio_seti (mp, param, value) + mio_setrange (mp, vs, ve, ndim) + n|EOF = mio_[gp]lseg[silrdx] (mp, ptr, mval, v, npix) + mio_close (mp) + + +2. Pixel Mask Interface (uses reference image for section transformation) + + pm = pm_newmask (ref_im, depth) + + pm = pm_open (bufptr|NULL) + pm = pm_create (naxes, axlen, depth) + pm = pm_newcopy (pm) + pm_close (pm) + + pm_[sg]size (pm, naxes, alxen, depth) + pm_seti (pm, param, value) + value = pm_stati (pm, param) + pm_debug (pm, outfd, maxcol, flags) + bool = pm_empty (pm) + pm_compress (pm) + pm_clear (pm) + + pm_load (pm, bufptr) + nwords = pm_save (pm, bufptr, buflen, save_flags) + pm_loadf (pm, fname, title, maxch) + pm_savef (pm, fname, title, save_flags) + pm_[load|save]im (pm, imname[, save_flags]) + + ptr = pm_emptyline (pm) + ptr = pm_access (pm, v) + bool = pm_linenotempty (pm, v) + bool = pm_sectnotempty (pm, vs, ve, ndim) + pm[gp]l[lrp][sil] (pm, v, buf, b_depth, npix, rop) + + pm_[set|get]plane (pm, v) + pm_point (pm, x, y, rop) + pm_circle (pm, x, y, r, rop) + pm_box (pm, x1,y1, x2,y2, rop) + pm_line (pm, x1,y1, x2,y2, width, rop) + pm_polygon (pm, x, y, npts, rop) + + pm_rop (pm_src, vs, pm_dst, vs, vn, rop) + pm_stencil (pm_src, vs, pm_dst, vs, pm_stl, vs, vn, rop) + + +2.1 Random Access to a Pixel Mask + + pmr = pmr_open (pm, plane, buflimit) + pmr_setrect (pmr, x1,y1, x2,y2) + mval = pmr_getpix (pmr, i, j) + pmr_close (pmr) + + +3. Pixel List Interface (stands alone; independent of IMIO; no coord xforms) + + pl = pl_open (bufptr|NULL) + pl = pl_create (naxes, axlen, depth) + pl = pl_newcopy (pl) + pl_close (pl) + + pl_[sg]size (pl, naxes, axlen, depth) + pl_seti (pl, param, value) + value = pl_stati (pl, param) + pl_debug (pl, outfd, maxcol, flags) + bool = pl_empty (pl) + pl_compress (pl) + pl_clear (pl) + + pl_load (pl, bufptr) + nwords = pl_save (pl, bufptr, buflen, save_flags) + pl_loadf (pl, fname, title, maxch) + pl_savef (pl, fname, title, save_flags) + pl_[load|save]im (pl, imname[, save_flags]) + + ptr = pl_emptyline (pl) + ptr = pl_access (pl, v) + bool = pl_linenotempty (pl, v) + bool = pl_sectnotempty (pl, vs, ve, ndim) + pl[gp]l[lrp][sil] (pl, v, buf, b_depth, npix, rop) + + pl_[set|get]plane (pl, v) + pl_point (pl, x, y, rop) + pl_circle (pl, x, y, r, rop) + pl_box (pl, x1,y1, x2,y2, rop) + pl_line (pl, x1,y1, x2,y2, width, rop) + pl_polygon (pl, x, y, npts, rop) + + pl_rop (pl_src, vs, pl_dst, vs, vn, rop) + pl_stencil (pl_src, vs, pl_dst, vs, pl_stl, vs, vn, rop) + + +3.1 Random Access to a Pixel List + + plr = plr_open (pl, plane, buflimit) + plr_setrect (plr, x1,y1, x2,y2) + mval = plr_getpix (plr, i, j) + plr_getlut (plr, bufp, xsize,ysize, xblock,yblock) + plr_close (plr) + + +3.2 Pixel, Line, and Range List Routines + + pl_pixrop (px_src, xs, src_maxval, + px_dst, ds, dst_maxval, npix, rop) + pl_linerop (ll_src, xs, src_maxval, + ll_dst, ds, dst_maxval, ll_out, npix, rop) + pl_rangerop (rl_src, xs, src_maxval, + rl_dst, ds, dst_maxval, rl_out, npix, rop) + pl_linestencil (ll_src, xs, src_maxval, ll_dst, ds, dst_maxval, + ll_stn, xs, ll_out, npix, rop) + + n = pl_[lrp]2[lrp][sil] (op_src, xs, op_dst, npix) + + len = pl_llen (ll) + + +4. EXAMPLE + +4.1 Sample Mask (pl_draw output) + + 40 .1111111..............................................................22222 + 39 .1111111..............................................................22222 + 38 .1111111...............................................................2222 + 37 .1111111...............................................................2222 + 36 .1111111............................................................4...... + 35 .1111111.....................11111111111111111111111111...........4444..... + 34 .1111111.....................11111111111111111111111111........44444444.... + 33 .1111111......................1111111111111111111111111......44444444...... + 32 .1111111......................1111111111111111111111111...44444444......... + 31 .1111111......................1111111111111111111111111.44444444........... + 30 .1111111...........4..........1111111111111111111111115444444.............. + 29 .1111111...........4..........11111111111111111111155554444................ + 28 .1111111...........4..........111111111111111111155555544.................. + 27 .1111111...........4..........1111111111111111555555551.................... + 26 .1111111.....................11111111111111155555555111.................... + 25 .1111111.....................11111111111115555555111111.................... + 24 ............................1111111111155444444.1111111.................... + 23 ...........................111111111155544444....111111.................... + 22 ..............1...........1111111155555444........11111.................... + 21 ........................1111111155555554..........11111.................... + 20 ........................111111555555511...........11111.................... + 19 ........................111555555551111...........11111.................... + 18 ........................155555555111111...........11111.................... + 17 ......................445555551111111111.........111111.................... + 16 ....................444455551111111111111.......1111111.................... + 15 ..................4444445111111111111111111111111111111.................... + 14 ...............44444444.1111111111111111111111111111111.................... + 13 .............44444444...................................................... + 12 ..........44444444......................................................... + 11 ........44444444........................................................... + 10 .........4444........................22222................................. + 9 ..........4.........................2222222..............22222............. + 8 ....................................2222222.............2222222............ + 7 ....................................2222222.............2222222............ + 6 .....................................22222..............2222222............ + 5 11111111111111111111.....................................22222............. + 4 11111111111111111111....................................................... + 3 11111111111111111111....................................................... + 2 11111111111111111111....................................................... + 1 11111111111111111111....................................................... + 123456789012345678901234567890123456789012345678901234567890123456789012345 + 1 2 3 4 5 6 7 + + +4.2 Sample Debug Output (for above mask) + +Mask 1EECD naxes=2 [75,40] maxval=177 plane=[75,40] +max buffered line size 1024, max actual line size 16 +40 lines total, 40 are nonempty, mask is nonempty +llbp=42AF5, len=1190, op=583, free=189, nupdates=35 +Index at 1EFF1 containing 40 lines: + 4 4 4 4 17 26 35 35 166 177 187 + 194 201 208 218 228 241 254 266 554 292 568 + 319 333 347 360 492 507 523 539 423 435 447 + 459 471 483 148 148 157 157 +Line list containing 40 lines: +[1:4] IH48(49) H20 Z55 (75,49) +[5] IH48(49) H20 IH1(50) Z37 H5 Z13 (75,50) +[6] IH49(50) Z37 H5 Z14 H7 Z12 (75,50) +[7:8] IH49(50) Z36 H7 Z13 H7 Z12 (75,50) +[9] IH51(52) P11 DH2(50) Z25 H7 Z14 H5 Z13 (75,50) +[10] IH51(52) Z9 H4 DH2(50) Z24 H5 Z33 (75,50) +[11] IH51(52) Z8 H8 Z59 (75,52) +[12] IH51(52) Z10 H8 Z57 (75,52) +[13] IH51(52) Z13 H8 Z54 (75,52) +[14] IH51(52) Z15 H8 DH3(49) Z1 H31 Z20 (75,49) +[15] IH51(52) Z18 H6 IS1(53) DH4(49) H30 Z20 (75,49) +[16] IH51(52) Z20 H4 IH1(53) H4 DH4(49) H13 Z7 H7 Z20 (75,49) +[17] IH51(52) Z22 H2 IH1(53) H6 DH4(49) H10 Z9 H6 Z20 (75,49) +[18] IH48(49) P25 IH4(53) H8 DH4(49) H6 Z11 H5 Z20 (75,49) +[19] IH48(49) Z24 H3 IH4(53) H8 DH4(49) H4 Z11 H5 Z20 (75,49) +[20] IH48(49) Z24 H6 IH4(53) H7 DH4(49) H2 Z11 H5 Z20 (75,49) +[21] IH48(49) Z24 H8 IH4(53) H7 DS1(52) DH3(49) Z10 H5 Z20 (75,49) +[22] IH48(49) P15 Z11 H8 IH4(53) H5 DH1(52) H3 DH3(49) Z8 H5 Z20 (75,49) +[23] IH48(49) Z27 H10 IH4(53) H3 DH1(52) H5 DH3(49) Z4 H6 Z20 (75,49) +[24] IH48(49) Z28 H11 IH4(53) H2 DH1(52) H6 DH3(49) Z1 H7 Z20 (75,49) +[25] IH48(49) Z1 H7 Z21 H13 IH4(53) H7 DH4(49) H6 Z20 (75,49) +[26] IH48(49) Z1 H7 Z21 H15 IH4(53) H8 DH4(49) H3 Z20 (75,49) +[27] IH48(49) Z1 H7 IH3(52) P12 DH3(49) Z10 H16 IH4(53) H8 DS4(49) Z20 + (75,49) +[28] IH48(49) Z1 H7 IH3(52) P12 DH3(49) Z10 H19 IH4(53) H6 DH1(52) H2 Z18 + (75,52) +[29] IH48(49) Z1 H7 IH3(52) P12 DH3(49) Z10 H21 IH4(53) H4 DH1(52) H4 Z16 + (75,52) +[30] IH48(49) Z1 H7 IH3(52) P12 DH3(49) Z10 H24 IS4(53) DH1(52) H6 Z14 + (75,52) +[31] IH48(49) Z1 H7 Z22 H25 IH3(52) Z1 H8 Z11 (75,52) +[32] IH48(49) Z1 H7 Z22 H25 IH3(52) Z3 H8 Z9 (75,52) +[33] IH48(49) Z1 H7 Z22 H25 IH3(52) Z6 H8 Z6 (75,52) +[34] IH48(49) Z1 H7 Z21 H26 IH3(52) Z8 H8 Z4 (75,52) +[35] IH48(49) Z1 H7 Z21 H26 IH3(52) Z11 H4 Z5 (75,52) +[36] IH48(49) Z1 H7 IH3(52) P61 Z6 (75,52) +[37:38] IH48(49) Z1 H7 IH1(50) Z63 H4 (75,50) +[39:40] IH48(49) Z1 H7 IH1(50) Z62 H5 (75,50) + +Line list containing 40 lines: +[1:4] 1-20(49) +[5] 1-20(49) 58-62(50) +[6] 38-42(50) 57-63(50) +[7:8] 37-43(50) 57-63(50) +[9] 11(52) 37-43(50) 58-62(50) +[10] 10-13(52) 38-42(50) +[11] 9-16(52) +[12] 11-18(52) +[13] 14-21(52) +[14] 16-23(52) 25-55(49) +[15] 19-24(52) 25(53) 26-55(49) +[16] 21-24(52) 25-28(53) 29-41(49) 49-55(49) +[17] 23-24(52) 25-30(53) 31-40(49) 50-55(49) +[18] 25(49) 26-33(53) 34-39(49) 51-55(49) +[19] 25-27(49) 28-35(53) 36-39(49) 51-55(49) +[20] 25-30(49) 31-37(53) 38-39(49) 51-55(49) +[21] 25-32(49) 33-39(53) 40(52) 51-55(49) +[22] 15(49) 27-34(49) 35-39(53) 40-42(52) 51-55(49) +[23] 28-37(49) 38-40(53) 41-45(52) 50-55(49) +[24] 29-39(49) 40-41(53) 42-47(52) 49-55(49) +[25] 2-8(49) 30-42(49) 43-49(53) 50-55(49) +[26] 2-8(49) 30-44(49) 45-52(53) 53-55(49) +[27] 2-8(49) 20(52) 31-46(49) 47-54(53) 55(49) +[28] 2-8(49) 20(52) 31-49(49) 50-55(53) 56-57(52) +[29] 2-8(49) 20(52) 31-51(49) 52-55(53) 56-59(52) +[30] 2-8(49) 20(52) 31-54(49) 55(53) 56-61(52) +[31] 2-8(49) 31-55(49) 57-64(52) +[32] 2-8(49) 31-55(49) 59-66(52) +[33] 2-8(49) 31-55(49) 62-69(52) +[34] 2-8(49) 30-55(49) 64-71(52) +[35] 2-8(49) 30-55(49) 67-70(52) +[36] 2-8(49) 69(52) +[37:38] 2-8(49) 72-75(50) +[39:40] 2-8(49) 71-75(50) diff --git a/sys/plio/mkpkg b/sys/plio/mkpkg new file mode 100644 index 00000000..deb49757 --- /dev/null +++ b/sys/plio/mkpkg @@ -0,0 +1,94 @@ +# Make the PLIO package library. + +$checkout libex.a lib$ +$update libex.a +$checkin libex.a lib$ +$exit + +tfiles: + $set GFLAGS = "-k -t sil -p tf/" + $ifolder (tf/plglpi.x, plglp.gx) $generic $(GFLAGS) plglp.gx $endif + $ifolder (tf/plglri.x, plglr.gx) $generic $(GFLAGS) plglr.gx $endif + $ifolder (tf/pll2pi.x, pll2p.gx) $generic $(GFLAGS) pll2p.gx $endif + $ifolder (tf/pll2ri.x, pll2r.gx) $generic $(GFLAGS) pll2r.gx $endif + $ifolder (tf/plp2li.x, plp2l.gx) $generic $(GFLAGS) plp2l.gx $endif + $ifolder (tf/plp2ri.x, plp2r.gx) $generic $(GFLAGS) plp2r.gx $endif + $ifolder (tf/plplpi.x, plplp.gx) $generic $(GFLAGS) plplp.gx $endif + $ifolder (tf/plplri.x, plplr.gx) $generic $(GFLAGS) plplr.gx $endif + $ifolder (tf/plpropi.x, plprop.gx) $generic $(GFLAGS) plprop.gx $endif + $ifolder (tf/plr2li.x, plr2l.gx) $generic $(GFLAGS) plr2l.gx $endif + $ifolder (tf/plr2pi.x, plr2p.gx) $generic $(GFLAGS) plr2p.gx $endif + $ifolder (tf/plrropi.x, plrrop.gx) $generic $(GFLAGS) plrrop.gx $endif + $ifolder (tf/plrpri.x, plrpr.gx) $generic $(GFLAGS) plrpr.gx $endif + $ifolder (tf/plreqi.x, plreq.gx) $generic $(GFLAGS) plreq.gx $endif + ; + +zzdebug: +zzdebug.e: + $set XFLAGS = "$(XFLAGS) -q" + $omake zzdebug.x <error.h> <ctype.h> <fset.h> <plset.h> <plio.h> + $link -z zzdebug.o -o zzdebug.e + ; + +libex.a: + # Retranslate any recently modified generic sources. + $ifeq (hostid, unix) + $call tfiles + $endif + + @tf # Update datatype expanded files. + + placcess.x <plio.h> <plset.h> + plalloc.x <plio.h> + plascii.x <ctype.h> <plset.h> + plbox.x <plio.h> <plset.h> plbox.h + plubox.x <plio.h> <plset.h> plbox.h + plcircle.x <plio.h> <plset.h> plcircle.h + plucircle.x <plio.h> <plset.h> plcircle.h + plclear.x <plio.h> + plclose.x <plio.h> + plcmpress.x <plio.h> + plcompare.x <plio.h> <plset.h> + plcreate.x + pldbgout.x + pldebug.x <plio.h> <plset.h> + plempty.x <plio.h> + plemptyline.x <plio.h> + plglls.x <plio.h> + plgplane.x <plio.h> + plgsize.x <plio.h> <plset.h> + pllen.x <plio.h> + plleq.x <plio.h> + plline.x <math.h> <plio.h> <plset.h> + pllinene.x <plio.h> <plset.h> + pllnext.x pllseg.h <plio.h> + plload.x <plio.h> <plset.h> + plloadf.x <plio.h> <plset.h> + plloadim.x <imhdr.h> <imset.h> <plio.h> <plset.h> + plloop.x <plio.h> + pllpr.x <plio.h> + pllrop.x <plio.h> <plset.h> pllseg.h + pllsten.x <plio.h> <plset.h> pllseg.h + plnewcopy.x <plio.h> <plset.h> + plopen.x <plio.h> <plset.h> + plplls.x <plio.h> + plpoint.x <plio.h> <plset.h> + plpolygon.x <plio.h> <plset.h> plpolygon.h + plupolygon.x <plio.h> <plset.h> plpolygon.h + plregrop.x <plio.h> <plset.h> + plrio.x <plio.h> + plrop.x <plio.h> <plset.h> + plsave.x <plio.h> <plset.h> + plsavef.x <plio.h> <plset.h> + plsaveim.x <imhdr.h> <imset.h> <mach.h> <plio.h> <plset.h> + plsectnc.x <plio.h> pllseg.h <plset.h> + plsectne.x <plio.h> pllseg.h <plset.h> + plseti.x <plio.h> <plset.h> + plsplane.x <plio.h> + plssize.x <plio.h> <plset.h> + plsslv.x <plio.h> <plset.h> + plstati.x <plio.h> <plset.h> + plsten.x <plio.h> <plset.h> + plupdate.x <mach.h> <plio.h> <plset.h> + plvalid.x <plio.h> + ; diff --git a/sys/plio/placcess.x b/sys/plio/placcess.x new file mode 100644 index 00000000..92cb036d --- /dev/null +++ b/sys/plio/placcess.x @@ -0,0 +1,59 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <plset.h> +include <plio.h> + +# PL_ACCESS -- Return a pointer (type short) to the encoded line list data +# for the indicated mask image line. A valid pointer is always returned; +# if the mask line is empty, the pointer will point to "empty line" linelist. + +pointer procedure pl_access (pl, v) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I coordinates of desired line + +int pl_reference() + +begin + return (Ref (pl, pl_reference(pl,v))) +end + + +# PL_REFERENCE -- Return a reference (llbuf offset) to the indicated mask +# image line. A valid offset is always returned; if the mask line is empty, +# the offset will be that of the "empty line" linelist. + +int procedure pl_reference (pl, v) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I coordinates of desired line + +int index, i +int totlen, axlen +define oob_ 91 + +begin + # Compute the index of the line in the line pointer array. + if (PL_NAXES(pl) == 2) { + # Optimized for case naxes=2. + index = v[2] + if (index < 1 || index > PL_AXLEN(pl,2)) + goto oob_ + } else { + # General case. + index = 1 + totlen = 1 + do i = 2, PL_NAXES(pl) { + axlen = PL_AXLEN(pl,i) + if (v[i] < 1 || v[i] > axlen) + goto oob_ + index = index + totlen * (v[i] - 1) + totlen = totlen * axlen + } + } + + return (PL_LP(pl,index)) +oob_ + call syserr (SYS_PLREFOOB) +end diff --git a/sys/plio/plalloc.x b/sys/plio/plalloc.x new file mode 100644 index 00000000..1fecf486 --- /dev/null +++ b/sys/plio/plalloc.x @@ -0,0 +1,39 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_ALLOC -- Allocate space in the line list buffer, returning the llbuf +# offset of the allocated area as the function value. If overflow occurs +# the buffer is resized. + +int procedure pl_alloc (pl, nwords) + +pointer pl #I mask descriptor +int nwords #I number of words of storage to allocate + +int newbuf +int len, o_len, inc, op +errchk realloc + +begin + len = PL_LLLEN(pl) # current buffer length + inc = PL_LLINC(pl) # length increment + op = PL_LLOP(pl) # next available location + + newbuf = op + op = newbuf + nwords + + for (o_len = len; op >= len; ) { + inc = min (PL_MAXINC, inc * 2) + len = len + inc + } + + if (len != o_len) + call realloc (PL_LLBP(pl), len, TY_SHORT) + + PL_LLLEN(pl) = len + PL_LLINC(pl) = inc + PL_LLOP(pl) = op + + return (newbuf) +end diff --git a/sys/plio/plascii.x b/sys/plio/plascii.x new file mode 100644 index 00000000..8106b10e --- /dev/null +++ b/sys/plio/plascii.x @@ -0,0 +1,66 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <ctype.h> +include <plset.h> + +# PL_ASCIIDUMP -- Dump a two dimensional region of a mask as a printable ASCII +# character array on the output stream. Intended as a simple debugging tool; +# see also PL_SAVEIM. + +procedure pl_asciidump (pl, vs, ve, outfd) + +pointer pl #I mask descriptor +long vs[ARB] #I ll vector (only first two elements used) +long ve[ARB] #I ur vector (only first two elements used) +int outfd #I output file + +pointer sp, pv, cv +int npix, ch, i +long v[PL_MAXDIM] +errchk pl_valid + +begin + call pl_valid (pl) + npix = ve[1] - vs[1] + 1 + + call smark (sp) + call salloc (pv, npix, TY_INT) + call salloc (cv, npix, TY_CHAR) + + # Output mask. + call amovl (vs, v, PL_MAXDIM) + v[2] = ve[2] + + while (v[2] >= vs[2]) { + call pl_glpi (pl, v, Memi[pv], 0, npix, PIX_SRC) + do i = 1, npix { + ch = mod (Memi[pv+i-1], 128) + if (ch < 32) + ch = ch + 32 + if (ch <= 32 || ch == 127) + ch = '.' + Memc[cv+i-1] = ch + } + call fprintf (outfd, "%3d ") + call pargi (v[2]) + call write (outfd, Memc[cv], npix) + call putci (outfd, '\n') + v[2] = v[2] - 1 + } + + # Label the columns. + call fprintf (outfd, "%5t") + do i = 1, npix + call putci (outfd, TO_DIGIT(mod (i,10))) + call fprintf (outfd, "\n") + + call fprintf (outfd, "%5t") + do i = 1, npix + if (mod (i, 10) == 0) + call putci (outfd, TO_DIGIT(i / 10)) + else + call putci (outfd, ' ') + call fprintf (outfd, "\n") + + call sfree (sp) +end diff --git a/sys/plio/plbox.h b/sys/plio/plbox.h new file mode 100644 index 00000000..f988b9d6 --- /dev/null +++ b/sys/plio/plbox.h @@ -0,0 +1,10 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +define LEN_BOXDES 6 +define B_PL Memi[$1] # reference mask +define B_X1 Memi[$1+1] # X1 coord of box +define B_Y1 Memi[$1+2] # Y1 coord of box +define B_X2 Memi[$1+3] # X2 coord of box +define B_Y2 Memi[$1+4] # Y2 coord of box +define B_PV Memi[$1+5] # pixel value + diff --git a/sys/plio/plbox.x b/sys/plio/plbox.x new file mode 100644 index 00000000..35dbda4c --- /dev/null +++ b/sys/plio/plbox.x @@ -0,0 +1,37 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> +include "plbox.h" + + +# PL_BOX -- Rasterop between a box as source, and an existing mask as dest. +# This is a 2-dim operator. The pl_setplane procedure is used to specify +# the plane to be modified. + +procedure pl_box (pl, x1,y1, x2,y2, rop) + +pointer pl #I mask descriptor +int x1,y1 #I lower left corner of box +int x2,y2 #I upper right corner of box +int rop #I rasterop + +pointer sp, ufd +extern pl_ubox() + +begin + call plvalid (pl) + call smark (sp) + call salloc (ufd, LEN_BOXDES, TY_STRUCT) + + B_PL(ufd) = pl + B_X1(ufd) = max(1, min(PL_AXLEN(pl,1), x1)) + B_Y1(ufd) = max(1, min(PL_AXLEN(pl,2), y1)) + B_X2(ufd) = max(1, min(PL_AXLEN(pl,1), x2)) + B_Y2(ufd) = max(1, min(PL_AXLEN(pl,2), y2)) + B_PV(ufd) = 1 + + call pl_regionrop (pl, pl_ubox, ufd, y1, y2, rop) + + call sfree (sp) +end diff --git a/sys/plio/plcircle.h b/sys/plio/plcircle.h new file mode 100644 index 00000000..f77492f9 --- /dev/null +++ b/sys/plio/plcircle.h @@ -0,0 +1,10 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + + +define LEN_CIRCLEDES 5 +define C_PL Memi[$1] # reference mask +define C_XCEN Memr[P2R($1+1)] # X1 coord of circle +define C_YCEN Memr[P2R($1+2)] # Y1 coord of circle +define C_RADIUS Memr[P2R($1+3)] # X2 coord of circle +define C_PV Memi[$1+4] # pixel value + diff --git a/sys/plio/plcircle.x b/sys/plio/plcircle.x new file mode 100644 index 00000000..504c1ce5 --- /dev/null +++ b/sys/plio/plcircle.x @@ -0,0 +1,43 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> +include "plcircle.h" + + +# PL_CIRCLE -- Rasterop between a circular region as source, and an existing +# mask as destination. It is not necessary for the center of the circle to +# be inside the mask; if it is outside, the boundary of the circle will be +# clipped to the boundary of the mask. This is a 2-dim operator. If the +# image dimensionality is greater than two the pl_setplane procedure should +# be called first to specify the plane to be modified. + +procedure pl_circle (pl, x, y, radius, rop) + +pointer pl #I mask descriptor +int x,y #I center coords of circle +int radius #I radius of circle +int rop #I rasterop + +int y1, y2 +pointer sp, ufd +extern pl_ucircle() + +begin + call plvalid (pl) + call smark (sp) + call salloc (ufd, LEN_CIRCLEDES, TY_STRUCT) + + y1 = max ( 1, min (PL_AXLEN(pl,2), y - radius)) + y2 = max (y1, min (PL_AXLEN(pl,2), y + radius)) + + C_PL(ufd) = pl + C_XCEN(ufd) = x + C_YCEN(ufd) = y + C_RADIUS(ufd) = radius + C_PV(ufd) = 1 + + call pl_regionrop (pl, pl_ucircle, ufd, y1, y2, rop) + + call sfree (sp) +end diff --git a/sys/plio/plclear.x b/sys/plio/plclear.x new file mode 100644 index 00000000..5ece1b5d --- /dev/null +++ b/sys/plio/plclear.x @@ -0,0 +1,32 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_CLEAR -- Clear a mask. The entire surface is cleared. This is equivalent +# to a full surface pl_rop with rop=PIX_CLR, but is more convenient and can be +# implemented more efficiently since the entire surface is cleared. + +procedure pl_clear (pl) + +pointer pl #I mask descriptor + +pointer lp +int n_len, i +errchk realloc + +begin + # Clear the line list buffer. + lp = Ref (pl, PL_EMPTYLINE) + PL_LLOP(pl) = LP_BLEN(lp) + LP_NREFS(lp) = PL_NLP(pl) + + do i = 1, PL_NLP(pl) + PL_LP(pl,i) = PL_EMPTYLINE + + n_len = PL_LLBUFLEN + call realloc (PL_LLBP(pl), n_len, TY_SHORT) + + PL_LLLEN(pl) = n_len + PL_LLFREE(pl) = 0 + PL_LLNUPDATES(pl) = 0 +end diff --git a/sys/plio/plclose.x b/sys/plio/plclose.x new file mode 100644 index 00000000..e5e53e2b --- /dev/null +++ b/sys/plio/plclose.x @@ -0,0 +1,26 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <plio.h> + +# PL_CLOSE -- Close a mask descriptor. The memory resident mask is destroyed; +# an explicit call to one of the save procedures is required to save the mask +# in external storage. + +procedure pl_close (pl) + +pointer pl #I mask descriptor +errchk syserr + +begin + if (pl != NULL) { + if (PL_MAGIC(pl) != PL_MAGICVAL) + call syserr (SYS_PLINVDES) + + if (PL_LPP(pl) != NULL) + call mfree (PL_LPP(pl), TY_INT) + if (PL_LLBP(pl) != NULL) + call mfree (PL_LLBP(pl), TY_SHORT) + call mfree (pl, TY_STRUCT) + } +end diff --git a/sys/plio/plcmpress.x b/sys/plio/plcmpress.x new file mode 100644 index 00000000..54850a7a --- /dev/null +++ b/sys/plio/plcmpress.x @@ -0,0 +1,90 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <plio.h> + +# PL_COMPRESS -- Compress the line list buffer to eliminate any unusable +# space, as is generated when mask lines are modified and the old line lists +# are freed. The compress operation may move the line lists about, possibly +# changing the line offsets. + +procedure pl_compress (pl) + +pointer pl #I mask descriptor + +pointer n_bp, o_lp, n_lp, op +int nwords, r_len, b_len, i +errchk malloc, mfree, syserr + +begin + # Redundant calls are ignored. + if (PL_LLNUPDATES(pl) <= 0) + return + + # Return if there was a prior error with plalloc. + if (PL_LLBP(pl) == NULL) + call syserr (SYS_PLBADMASK) + + # Count the total space in the active line lists. + nwords = 0 + for (i=0; i < PL_LLOP(pl); i=i+b_len) { + o_lp = Ref (pl, i) + b_len = LP_BLEN(o_lp) + if (b_len <= 0 || b_len > PL_LLOP(pl)) + call syserr (SYS_PLBADMASK) + if (i == PL_EMPTYLINE || LP_NREF(o_lp) > 0) + nwords = nwords + LP_LEN(o_lp) + } + + # Verify that the free space accounting is correct. + if (nwords != (PL_LLOP(pl) - PL_LLFREE(pl))) + call eprintf ("Warning: PL_LLFREE inconsistent (recoverable)\n") + + # Allocate a new buffer large enough to hold the compressed line list. + call malloc (n_bp, nwords, TY_SHORT) + + # Copy the active line lists to the new buffer; as each line is + # copied, overwrite a couple words of the old line list with the + # new offset of the line. + + op = 0 + for (i=0; i < PL_LLOP(pl); i=i+b_len) { + o_lp = Ref (pl, i) + b_len = LP_BLEN(o_lp) + if (b_len <= 0 || b_len > PL_LLOP(pl)) + call syserr (SYS_PLBADMASK) + + if (i == PL_EMPTYLINE || LP_NREF(o_lp) > 0) { + n_lp = n_bp + op + r_len = LP_LEN(o_lp) + + # The following should not be possible, barring a bug. + if (op + r_len > nwords) + call fatal (pl, "pl_compress: llbuf overflow") + + call amovs (Mems[o_lp], Mems[n_lp], r_len) + + LP_NREFS(o_lp) = op / I_SHIFT + LP_SETBLEN(o_lp, mod (op, I_SHIFT)) + LP_SETBLEN(n_lp, r_len) + op = op + r_len + } + } + + # Fix up the line index by accessing the tag word in the old line list + # in the old buffer to get the line list offset in the new buffer. + + do i = 1, PL_NLP(pl) { + o_lp = Ref (pl, PL_LP(pl,i)) + PL_LP(pl,i) = LP_NREF(o_lp) * I_SHIFT + LP_BLEN(o_lp) + } + + # Deallocate the old buffer and install the new one. + call mfree (PL_LLBP(pl), TY_SHORT) + + PL_LLBP(pl) = n_bp + PL_LLOP(pl) = op + PL_LLLEN(pl) = nwords + PL_LLFREE(pl) = 0 + PL_LLNUPDATES(pl) = 0 +end diff --git a/sys/plio/plcompare.x b/sys/plio/plcompare.x new file mode 100644 index 00000000..59ba9d1f --- /dev/null +++ b/sys/plio/plcompare.x @@ -0,0 +1,35 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_COMPARE -- Compare two masks for equality, optionally noting any +# differences on the output file. PL_EQUAL is returned if the two masks +# are equivalent. + +int procedure pl_compare (pl_1, pl_2, outfd) + +pointer pl_1, pl_2 #I masks to be compared +int outfd #I file for diagnostic output, or NULL + +int i +bool pll_equal() + +begin + if (PL_NAXES(pl_1) != PL_NAXES(pl_2) || PL_NLP(pl_1) != PL_NLP(pl_2)) { + if (outfd != NULL) + call fprintf (outfd, "the masks are not the same size\n") + return (PL_NOTEQUAL) + } + + do i = 1, PL_NLP(pl_1) + if (!pll_equal (LL(pl_1,PL_LP(pl_1,i)), LL(pl_2,PL_LP(pl_2,i)))) { + if (outfd != NULL) { + call fprintf (outfd, "masks differ at line %d\n") + call pargi (i) + } + return (PL_NOTEQUAL) + } + + return (PL_EQUAL) +end diff --git a/sys/plio/plcreate.x b/sys/plio/plcreate.x new file mode 100644 index 00000000..fe972bcb --- /dev/null +++ b/sys/plio/plcreate.x @@ -0,0 +1,22 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# PL_CREATE -- Create an empty mask with the given dimensionality and size. +# A newly created mask has all line pointers pointing to the empty line, +# which is stored as the first entry in the line list buffer. + +pointer procedure pl_create (naxes, axlen, depth) + +int naxes #I number of axes (dimensionality of mask) +long axlen[ARB] #I length of each axis +int depth #I mask depth, bits + +pointer pl +pointer pl_open() +errchk pl_open + +begin + pl = pl_open (NULL) + call pl_ssize (pl, naxes, axlen, depth) + + return (pl) +end diff --git a/sys/plio/pldbgout.x b/sys/plio/pldbgout.x new file mode 100644 index 00000000..26885f3e --- /dev/null +++ b/sys/plio/pldbgout.x @@ -0,0 +1,47 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# PL_DEBUGOUT -- Output formatter for PL package debug output. Output as +# many text items as will fit on a line, inserting one space between each +# text item. A call with BUF=EOS terminates the sequence with a newline. + +procedure pl_debugout (fd, buf, col, firstcol, maxcol) + +int fd #I output stream +char buf[ARB] #I text to be output +int col #I next column of output +int firstcol #I first column to write to +int maxcol #I last column to write to + +int nchars +int strlen() + +begin + nchars = min (maxcol-firstcol+1, strlen(buf)) + + if (nchars == 0) { + # Terminate the sequence with a newline. + call fprintf (fd, "\n") + col = 1 + return + + } else if (col + nchars > maxcol) { + # Break line and output token. + call fprintf (fd, "\n") + + for (col=1; col < firstcol; col=col+1) + call putci (fd, ' ') + + } else { + # Append to the current line. + if (col <= firstcol) { + for (; col < firstcol; col=col+1) + call putci (fd, ' ') + } else { + call putci (fd, ' ') + col = col + 1 + } + } + + call putline (fd, buf) + col = col + nchars +end diff --git a/sys/plio/pldebug.x b/sys/plio/pldebug.x new file mode 100644 index 00000000..67a719dc --- /dev/null +++ b/sys/plio/pldebug.x @@ -0,0 +1,218 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_DEBUG -- Print debug information for a mask. The information to be +# printed is selected by summing the following bitflags: +# +# PD_SUMMARY mask level summary information +# PD_INDEX print the line list index +# PD_LLOUT print the line lists, line list format +# PD_RLOUT print the line lists, range list format +# +# The mask is not modified in any way. All output is on the given stream, +# formatted to the page width given by the 'width' argument. + +procedure pl_debug (pl, fd, width, what) + +pointer pl #I mask descriptor +int fd #I output file +int width #I max width of formatted output, columns +int what #I flags defining what to print + +pointer sp, buf, rng, rl, pp +int line_1, line_2, nne, nv, v, lp, i +int naxes, axlen, nlp, firstcol, maxcol, col, rlen +errchk pl_valid, fprintf, pl_debugout, pll_prints, plr_printi +bool pl_empty() +int pl_l2ri() + +define index_ 91 +define lines_ 92 +define done_ 93 +define llout_ 94 + +begin + call smark (sp) + call salloc (buf, SZ_LINE, TY_CHAR) + call salloc (rng, SZ_FNAME, TY_CHAR) + call salloc (rl, RL_MAXLEN(pl), TY_INT) + + call pl_valid (pl) + naxes = PL_NAXES(pl) + axlen = PL_AXLEN(pl,1) + nlp = PL_NLP(pl) + maxcol = width - 1 + + # Output the summary information. + # --------------------------------- + + if (and (what, PD_SUMMARY) == 0) + goto index_ + + # Line 1 of summary. + call fprintf (fd, "Mask %x naxes=%d [") + call pargi (pl) + call pargi (naxes) + do i = 1, naxes { + call fprintf (fd, "%d%c") + call pargi (PL_AXLEN(pl,i)) + if (i == naxes) + call pargi (']') + else + call pargi (',') + } + call fprintf (fd, " maxval=%o") + call pargi (PL_MAXVAL(pl)) + call fprintf (fd, " plane=[") + do i = 1, naxes { + call fprintf (fd, "%d%c") + call pargi (PL_AXLEN(pl,i)) + if (i == naxes) + call pargi (']') + else + call pargi (',') + } + call fprintf (fd, "\n") + + # Line 2 of summary. + call fprintf (fd, + "max buffered line size %d, max actual line size %d\n") + call pargi (PL_MAXLINE(pl)) + v = 0 + nne = 0 + do i = 1, nlp { + lp = PL_LP(pl,i) + nv = LP_LEN (Ref (pl, lp)) + if (nv > v) + v = nv + if (lp != PL_EMPTYLINE) + nne = nne + 1 + } + call pargi (v) + + # Line 3 of summary. + call fprintf (fd, "%d lines total, %d are nonempty, mask is %s\n") + call pargi (nlp) + call pargi (nne) + if (pl_empty (pl)) + call pargstr ("empty") + else + call pargstr ("nonempty") + + # Line 4 of summary. + call fprintf (fd, "llbp=%x, len=%d, op=%d, free=%d, nupdates=%d\n") + call pargi (PL_LLBP(pl)) + call pargi (PL_LLLEN(pl)) + call pargi (PL_LLOP(pl)) + call pargi (PL_LLFREE(pl)) + call pargi (PL_LLNUPDATES(pl)) + +index_ + # Print index. + # --------------------------------- + + if (and (what, PD_INDEX) == 0) + goto lines_ + + call fprintf (fd, "Index at %x containing %d lines:\n") + call pargi (PL_LPP(pl)) + call pargi (nlp) + col = 1 + firstcol = 1 + do i = 1, nlp { + lp = PL_LP(pl,i) + call sprintf (Memc[buf], SZ_LINE, "%6d") + call pargi (lp) + call pl_debugout (fd, Memc[buf], col, firstcol, maxcol) + } + call pl_debugout (fd, "", col, firstcol, maxcol) + +lines_ + # Print the line list. + # --------------------------------- + + if (and (what, PD_LLOUT+PD_RLOUT+PD_LHDR) == 0) + goto done_ + + call fprintf (fd, "Line list containing %d lines:\n") + call pargi (nlp) + + line_1 = 0 + do i = 1, nlp + 1 { + if (i > nlp && line_1 != 0) + goto llout_ + lp = PL_LP(pl,i) + + if (lp == PL_EMPTYLINE && line_1 == 0) { + # Skip over an empty line. + next + } else if (line_1 == 0) { + # Begin a new region. + line_1 = i + line_2 = i + if (i == nlp) + goto llout_ + } else if (lp == PL_LP(pl,line_1)) { + # Add line to current region. + line_2 = i + if (i == nlp) + goto llout_ + + } else { + # Output a region. +llout_ + lp = PL_LP(pl,line_1) + pp = Ref (pl, lp) + + if (line_1 == line_2) { + call sprintf (Memc[rng], SZ_FNAME, "[%d]") + call pargi (line_1) + } else { + call sprintf (Memc[rng], SZ_FNAME, "[%d:%d]") + call pargi (line_1) + call pargi (line_2) + } + + if (and (what, PD_LHDR) != 0) { + call sprintf (Memc[buf], SZ_LINE, + "%s%12tlp=%5d, nref=%d, blen=%d, len=%d") + call pargstr (Memc[rng]) + call pargi (lp) + call pargi (LP_NREF(pp)) + call pargi (LP_BLEN(pp)) + call pargi (LP_LEN(pp)) + } else + call strcpy (Memc[rng], Memc[buf], SZ_LINE) + + # Output the line list as a line list. + firstcol = 12 + if (and (what, PD_LLOUT) != 0) + call pll_prints (LL(pl,lp), fd, Memc[buf], firstcol, maxcol) + + # Output as a range list. + if (and (what, PD_RLOUT) != 0) { + rlen = pl_l2ri (LL(pl,lp), 1, Memi[rl], axlen) + call plr_printi (Memi[rl], fd, Memc[buf], firstcol, maxcol) + } + + if (and (what, PD_RLOUT+PD_LLOUT) == 0) { + col = 1; firstcol = 1 + call pl_debugout (fd, Memc[buf], col, firstcol, maxcol) + call pl_debugout (fd, "", col, firstcol, maxcol) + } + + if (PL_LP(pl,i) == PL_EMPTYLINE || line_2 == i) + line_1 = 0 + else { + line_1 = i + line_2 = i + } + } + } + +done_ + call flush (fd) + call sfree (sp) +end diff --git a/sys/plio/plempty.x b/sys/plio/plempty.x new file mode 100644 index 00000000..2dab29ed --- /dev/null +++ b/sys/plio/plempty.x @@ -0,0 +1,25 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_EMPTY -- Test whether a mask is empty, i.e., contains no nonzero pixels. + +bool procedure pl_empty (pl) + +pointer pl #I mask descriptor +int i + +begin + # Mask is empty if all lines are empty. + do i = 1, PL_NLP(pl) + if (PL_LP(pl,i) != PL_EMPTYLINE) + return (false) + + return (true) + + # The following also works, but the call to pl_compress is an + # unintended side effect which it is best to avoid. + + # call pl_compress (pl) + # return (PL_LLOP(pl) == LP_BLEN(Ref(pl,0))) +end diff --git a/sys/plio/plemptyline.x b/sys/plio/plemptyline.x new file mode 100644 index 00000000..4d4612cd --- /dev/null +++ b/sys/plio/plemptyline.x @@ -0,0 +1,14 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + + +# PL_EMPTYLINE -- Return a pointer to the empty line for a mask. + +pointer procedure pl_emptyline (pl) + +pointer pl #I mask descriptor + +begin + return (Ref (pl, PL_EMPTYLINE)) +end diff --git a/sys/plio/plglls.x b/sys/plio/plglls.x new file mode 100644 index 00000000..aaae0e42 --- /dev/null +++ b/sys/plio/plglls.x @@ -0,0 +1,39 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_GLLS -- Get a line segment as a list list, applying the given ROP to +# combine the pixels with those of the output line list. + +procedure pl_glls (pl, v, ll_dst, ll_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +short ll_dst[ARB] #O output line list +int ll_depth #I line list depth, bits +int npix #I number of pixels desired +int rop #I rasterop + +int ll_len +pointer sp, ll_out, ll_src +pointer pl_access() +errchk pl_access + +begin + ll_src = pl_access (pl,v) + if (!R_NEED_DST(rop) && v[1] == 1 && npix == PL_AXLEN(pl,1)) { + ll_len = LP_LEN(ll_src) + call amovs (Mems[ll_src], ll_dst, ll_len) + + } else { + call smark (sp) + call salloc (ll_out, LL_MAXLEN(pl), TY_SHORT) + + call pl_linerop (Mems[ll_src], v[1], PL_MAXVAL(pl), ll_dst, 1, + MV(ll_depth), Mems[ll_out], npix, rop) + ll_len = LP_LEN(ll_out) + call amovs (Mems[ll_out], ll_dst, ll_len) + + call sfree (sp) + } +end diff --git a/sys/plio/plglp.gx b/sys/plio/plglp.gx new file mode 100644 index 00000000..d5803033 --- /dev/null +++ b/sys/plio/plglp.gx @@ -0,0 +1,38 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_GLP -- Get a line segment as a pixel array, applying the given ROP to +# combine the pixels with those of the output array. + +procedure pl_glp$t (pl, v, px_dst, px_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +PIXEL px_dst[ARB] #O output pixel array +int px_depth #I pixel depth, bits +int npix #I number of pixels desired +int rop #I rasterop + +int np +pointer sp, px_out, ll_src +pointer pl_access() +int pl_l2p$t() +errchk pl_access + +begin + ll_src = pl_access (pl,v) + if (!R_NEED_DST(rop)) { + np = pl_l2p$t (Mems[ll_src], v[1], px_dst, npix) + return + } + + call smark (sp) + call salloc (px_out, npix, TY_PIXEL) + + np = pl_l2p$t (Mems[ll_src], v[1], Mem$t[px_out], npix) + call pl_pixrop$t (Mem$t[px_out], 1, PL_MAXVAL(pl), + px_dst, 1, MV(px_depth), npix, rop) + + call sfree (sp) +end diff --git a/sys/plio/plglr.gx b/sys/plio/plglr.gx new file mode 100644 index 00000000..3a63346d --- /dev/null +++ b/sys/plio/plglr.gx @@ -0,0 +1,44 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> +include <plset.h> + +# PL_GLR -- Get a line segment as a range list, applying the given ROP to +# combine the pixels with those of the output list. + +procedure pl_glr$t (pl, v, rl_dst, rl_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +PIXEL rl_dst[ARB] #O output range list +int rl_depth #I range list depth, bits +int npix #I number of pixels desired +int rop #I rasterop + +int mr, nr +pointer sp, rl_out, rl_src, ll_src +pointer pl_access() +int pl_l2r$t() +errchk pl_access + +begin + ll_src = pl_access (pl,v) + if (!R_NEED_DST(rop)) + nr = pl_l2r$t (Mems[ll_src], v[1], rl_dst, npix) + else { + call smark (sp) + mr = min (RL_MAXLEN(pl), npix * 3) + call salloc (rl_src, mr, TY_PIXEL) + call salloc (rl_out, mr, TY_PIXEL) + + nr = pl_l2r$t (Mems[ll_src], v[1], Mem$t[rl_src], npix) + call pl_rangerop$t (Mem$t[rl_src], 1, PL_MAXVAL(pl), + rl_dst, 1, MV(rl_depth), + Mem$t[rl_out], npix, rop) + + # Copy out the edited range list. + call amov$t (Mem$t[rl_out], rl_dst, RL$T_LEN(rl_out)) + + call sfree (sp) + } +end diff --git a/sys/plio/plgplane.x b/sys/plio/plgplane.x new file mode 100644 index 00000000..3f338178 --- /dev/null +++ b/sys/plio/plgplane.x @@ -0,0 +1,15 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_GETPLANE -- Get the 2-Dim plane to be referenced in calls to the pl_box, +# pl_circle, etc. geometric region masking operators. + +procedure pl_getplane (pl, v) + +pointer pl #I mask descriptor +long v[ARB] #O vector defining plane + +begin + call amovl (PL_PLANE(pl,1), v, PL_MAXDIM) +end diff --git a/sys/plio/plgsize.x b/sys/plio/plgsize.x new file mode 100644 index 00000000..40e73ac3 --- /dev/null +++ b/sys/plio/plgsize.x @@ -0,0 +1,26 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_GSIZE -- Get the dimensionality and size of a mask. + +procedure pl_gsize (pl, naxes, axlen, depth) + +pointer pl #I mask descriptor +int naxes #O number of axes (dimensionality of mask) +long axlen[ARB] #O length of each axis +int depth #O mask depth, bits + +int i + +begin + naxes = PL_NAXES(pl) + call amovl (PL_AXLEN(pl,1), axlen, PL_MAXDIM) + + do i = 0, ARB + if (2**i > min (I_PVMAX, PL_MAXVAL(pl))) { + depth = i + break + } +end diff --git a/sys/plio/pll2p.gx b/sys/plio/pll2p.gx new file mode 100644 index 00000000..007af7a0 --- /dev/null +++ b/sys/plio/pll2p.gx @@ -0,0 +1,105 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_L2P -- Convert a line list to a pixel array. The number of pixels output +# (always npix) is returned as the function value. + +int procedure pl_l2p$t (ll_src, xs, px_dst, npix) + +short ll_src[ARB] #I input line list +int xs #I starting index in ll_src +PIXEL px_dst[ARB] #O output pixel array +int npix #I number of pixels to convert + +PIXEL pv +bool skipword +int opcode, data, ll_len, ll_first +int x1, x2, i1, i2, xe, np, ip, op, otop, i +define putpix_ 91 + +begin + # Support old format line lists. + if (LL_OLDFORMAT(ll_src)) { + ll_len = OLL_LEN(ll_src) + ll_first = OLL_FIRST + } else { + ll_len = LL_LEN(ll_src) + ll_first = LL_FIRST(ll_src) + } + + # No pixels? + if (npix <= 0 || ll_len <= 0) + return (0) + + xe = xs + npix - 1 + skipword = false + op = 1 + x1 = 1 + pv = 1 + + do ip = ll_first, ll_len { + if (skipword) { + skipword = false + next + } + + opcode = I_OPCODE(ll_src[ip]) + data = I_DATA(ll_src[ip]) + + switch (opcode) { + case I_ZN, I_HN, I_PN: + # Determine inbounds region of segment. + x2 = x1 + data - 1 + i1 = max (x1, xs) + i2 = min (x2, xe) + + # Process segment if any region is inbounds. + np = i2 - i1 + 1 + if (np > 0) { + otop = op + np - 1 + if (opcode == I_HN) { + do i = op, otop + px_dst[i] = pv + } else { + do i = op, otop + px_dst[i] = 0 + if (opcode == I_PN && i2 == x2) + px_dst[otop] = pv + } + op = otop + 1 + } + + # Advance the line index. + x1 = x2 + 1 + + case I_SH: + pv = (int(ll_src[ip+1]) * I_SHIFT) + data + skipword = true + case I_IH: + pv = pv + data + case I_DH: + pv = pv - data + case I_IS: + pv = pv + data + goto putpix_ + case I_DS: + pv = pv - data +putpix_ + if (x1 >= xs && x1 <= xe) { + px_dst[op] = pv + op = op + 1 + } + x1 = x1 + 1 + } + + if (x1 > xe) + break + } + + # Zero any remaining output range. + do i = op, npix + px_dst[i] = 0 + + return (npix) +end diff --git a/sys/plio/pll2r.gx b/sys/plio/pll2r.gx new file mode 100644 index 00000000..ae6a6fcf --- /dev/null +++ b/sys/plio/pll2r.gx @@ -0,0 +1,117 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_L2R -- Convert a line list to a range list. The length of the output +# range list is returned as the function value. + +int procedure pl_l2r$t (ll_src, xs, rl, npix) + +short ll_src[ARB] #I input line list +int xs #I starting index in ll_src +PIXEL rl[3,ARB] #O output range list +int npix #I number of pixels to convert + +int pv, hi +bool skipword +int opcode, data, ll_len, ll_first +int x1, x2, i1, i2, xe, np, rn, ip +define range_ 91 +define putrange_ 92 + +begin + # Support old format line lists. + if (LL_OLDFORMAT(ll_src)) { + ll_len = OLL_LEN(ll_src) + ll_first = OLL_FIRST + } else { + ll_len = LL_LEN(ll_src) + ll_first = LL_FIRST(ll_src) + } + + # No pixels? + if (npix <= 0 || ll_len <= 0) + return (0) + + rn = RL_FIRST + xe = xs + npix - 1 + skipword = false + x1 = 1 + hi = 1 + + do ip = ll_first, ll_len { + if (skipword) { + skipword = false + next + } + + opcode = I_OPCODE(ll_src[ip]) + data = I_DATA(ll_src[ip]) + + switch (opcode) { + case I_ZN: + pv = 0 + goto range_ + case I_HN: + pv = hi +range_ + # Determine inbounds region of segment. + x2 = x1 + data - 1 + i1 = max (x1, xs) + i2 = min (x2, xe) + np = i2 - i1 + 1 + x1 = x2 + 1 + + case I_PN: + pv = hi + x2 = x1 + data - 1 + if (x2 < xs || x2 > xe) + np = 0 + else { + i1 = x2 + np = 1 + } + x1 = x2 + 1 + + case I_SH: + hi = (int(ll_src[ip+1]) * I_SHIFT) + data + skipword = true + next + case I_IH: + hi = hi + data + next + case I_DH: + hi = hi - data + next + + case I_IS, I_DS: + if (opcode == I_IS) + hi = hi + data + else + hi = hi - data + + i1 = max (x1, xs) + i2 = min (x1, xe) + np = i2 - i1 + 1 + x1 = x1 + 1 + pv = hi + } + + # Output a range entry? + if (np > 0 && pv > 0) { + rl[1,rn] = i1 + rl[2,rn] = np + rl[3,rn] = pv + rn = rn + 1 + } + + if (x1 > xe) + break + } + + RL_LEN(rl) = rn - 1 + RL_AXLEN(rl) = npix + + return (rn - 1) +end diff --git a/sys/plio/pllen.x b/sys/plio/pllen.x new file mode 100644 index 00000000..a09b3770 --- /dev/null +++ b/sys/plio/pllen.x @@ -0,0 +1,14 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + + +# PL_LLEN -- Return the length of an encoded line list. + +int procedure pl_llen (ll) + +short ll[ARB] #I encoded line list + +begin + return (LL_LEN(ll)) +end diff --git a/sys/plio/plleq.x b/sys/plio/plleq.x new file mode 100644 index 00000000..d74ae370 --- /dev/null +++ b/sys/plio/plleq.x @@ -0,0 +1,44 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PLL_EQUAL -- Compare two line lists for equality. + +bool procedure pll_equal (l1, l2) + +short l1[ARB] #I line list 1 +short l2[ARB] #I line list 2 + +int i, off +int l1_len, l1_first +int l2_len, l2_first + +begin + # Support old format line lists. + if (LL_OLDFORMAT(l1)) { + l1_len = OLL_LEN(l1) + l1_first = OLL_FIRST + } else { + l1_len = LL_LEN(l1) + l1_first = LL_FIRST(l1) + } + + # Support old format line lists. + if (LL_OLDFORMAT(l2)) { + l2_len = OLL_LEN(l2) + l2_first = OLL_FIRST + } else { + l2_len = LL_LEN(l2) + l2_first = LL_FIRST(l2) + } + + if (l1_len != l2_len) + return (false) + + off = l2_first - l1_first + do i = l1_first, l1_len + if (l1[i] != l2[i+off]) + return (false) + + return (true) +end diff --git a/sys/plio/plline.x b/sys/plio/plline.x new file mode 100644 index 00000000..54caf253 --- /dev/null +++ b/sys/plio/plline.x @@ -0,0 +1,66 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <math.h> +include <plset.h> +include <plio.h> + +# PL_LINE -- Perform a rasterop operation upon a line of arbitrary width drawn +# at an arbitrary orientation in a 2-dimensional plane of a mask. If the +# dimensionality of the mask exceeds 2, the pl_setplane() procedure should be +# called first to define the plane of the mask to be modified. + +procedure pl_line (pl, x1, y1, x2, y2, width, rop) + +pointer pl #I mask descriptor +int x1,y1 #I start point of line +int x2,y2 #I end point of line +int width #I width of line to be drawn, pixels +int rop #I rasterop defining operation + +int npts +int x[4], y[4] +real theta, hwidth, dx, dy + +begin + dx = x2 - x1 + dy = y2 - y1 + + # Compute the line direction and halfwidth. + hwidth = max (1.0, real(width)) / 2.0 - 0.001 + if (abs(dx) < 0.0001) { + if (dy > 0) + theta = HALFPI + else + theta = -HALFPI + } else if (abs(dy) < 0.0001) { + if (dx > 0) + theta = 0.0 + else + theta = PI + } else + theta = atan2 (dy, dx) + + # Construct a polyline to be filled to draw the line. + if (width < 1.0001) { + x[1] = x1; y[1] = y1 + x[2] = x2; y[2] = y2 + npts = 2 + + } else { + x[1] = x1 + nint (hwidth * cos(theta+HALFPI)) + y[1] = y1 + nint (hwidth * sin(theta+HALFPI)) + + x[2] = x1 + nint (hwidth * cos(theta-HALFPI)) + y[2] = y1 + nint (hwidth * sin(theta-HALFPI)) + + x[3] = x2 + nint (hwidth * cos(theta-HALFPI)) + y[3] = y2 + nint (hwidth * sin(theta-HALFPI)) + + x[4] = x2 + nint (hwidth * cos(theta+HALFPI)) + y[4] = y2 + nint (hwidth * sin(theta+HALFPI)) + npts = 4 + } + + # Draw the line. + call pl_polygon (pl, x, y, npts, rop) +end diff --git a/sys/plio/pllinene.x b/sys/plio/pllinene.x new file mode 100644 index 00000000..3babc889 --- /dev/null +++ b/sys/plio/pllinene.x @@ -0,0 +1,17 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_LINENOTEMPTY -- Test whether the indicated mask image line is empty. + +bool procedure pl_linenotempty (pl, v) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I coordinates of desired line + +int pl_reference() + +begin + return (pl_reference(pl,v) != PL_EMPTYLINE) +end diff --git a/sys/plio/pllnext.x b/sys/plio/pllnext.x new file mode 100644 index 00000000..43d87c01 --- /dev/null +++ b/sys/plio/pllnext.x @@ -0,0 +1,61 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> +include "pllseg.h" + +# PLL_NEXTSEG -- Internal routine called by the PLLSEG.H routines to get the +# next segment of a line list. + +procedure pll_nextseg (ll, ld) + +short ll[ARB] #I input line list +int ld[LEN_PLLDES] #I list list i/o descriptor + +int ip +int opcode, data + +begin + for (ip = ld_ip(ld); ip <= LL_LEN(ll); ip = ld_ip(ld)) { + ld_ip(ld) = ip + 1 + opcode = I_OPCODE(ll[ip]) + data = I_DATA(ll[ip]) + + switch (opcode) { + case I_ZN: + ld_nleft(ld) = data + ld_value(ld) = 0 + return + case I_HN: + ld_nleft(ld) = data + ld_value(ld) = ld_hi(ld) + return + case I_PN: + ld_nleft(ld) = data - 1 + ld_value(ld) = 0 + ld_next_nleft(ld) = 1 + ld_next_value(ld) = ld_hi(ld) + return + + case I_SH: + ip = ip + 1 + ld_ip(ld) = ip + 1 + ld_hi(ld) = (int(ll[ip]) * I_SHIFT) + data + case I_IH: + ld_hi(ld) = ld_hi(ld) + data + case I_DH: + ld_hi(ld) = ld_hi(ld) - data + + case I_IS, I_DS: + if (opcode == I_IS) + ld_hi(ld) = ld_hi(ld) + data + else + ld_hi(ld) = ld_hi(ld) - data + + ld_nleft(ld) = 1 + ld_value(ld) = ld_hi(ld) + return + } + } + + ld_value(ld) = 0 +end diff --git a/sys/plio/plload.x b/sys/plio/plload.x new file mode 100644 index 00000000..d67fc595 --- /dev/null +++ b/sys/plio/plload.x @@ -0,0 +1,83 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <plset.h> +include <plio.h> + +# PL_LOAD -- Load a mask from a buffer encoded in a machine independent format +# in a previous call to PL_SAVE. The given mask descriptor may be either +# inactive or active. In the case of a load into an active mask, the existing +# mask is clobbered, and the mask may change size. + +procedure pl_load (pl, bp) + +pointer pl #I mask descriptor +pointer bp #I buffer pointer (to short) + +pointer sp, index, ex, ip +int o_lllen, o_nlp, sz_index, flags, nlp, i +errchk malloc, realloc, syserr +int pl_l2pi() +pointer coerce() + +begin + call smark (sp) + call salloc (ex, LEN_PLEXTERN, TY_STRUCT) + + o_lllen = PL_LLLEN(pl) + o_nlp = PL_NLP(pl) + + # Decode the external format header structure, a fixed size structure + # stored in 32 bit MII integer format. + + call miiupk32 (Memi[coerce(bp,TY_SHORT,TY_INT)], Memi[ex], + LEN_PLEXTERN, TY_STRUCT) + if (PLE_MAGIC(ex) != PL_MAGICVAL) + call syserr (SYS_PLBADSAVEF) + + call amovi (PLE_AXLEN(ex,1), PL_AXLEN(pl,1), PL_MAXDIM) + PL_MAGIC(pl) = PLE_MAGIC(ex) + PL_NAXES(pl) = PLE_NAXES(ex) + PL_LLOP(pl) = PLE_LLOP(ex) + PL_LLLEN(pl) = PLE_LLLEN(ex) + PL_MAXLINE(pl) = PLE_MAXLINE(ex) + PL_MAXVAL(pl) = PLE_MAXVAL(ex) + PL_NLP(pl) = PLE_NLP(ex) + sz_index = PLE_NLPX(ex) + flags = PLE_FLAGS(ex) + + # Get the (compressed) line index. If the descriptor is already active + # the new mask may be a different size than the old one. + + nlp = 1 + do i = 2, PL_NAXES(pl) + nlp = nlp * PL_AXLEN(pl,i) + if (PL_LPP(pl) == NULL) + call malloc (PL_LPP(pl), nlp, TY_INT) + else if (nlp != o_nlp) + call realloc (PL_LPP(pl), nlp, TY_INT) + + call salloc (index, sz_index, TY_SHORT) + #ip = bp + (LEN_PLEXTERN * SZ_STRUCT) / SZ_SHORT + ip = bp + (LEN_PLEXTERN * SZ_MII_INT) / SZ_SHORT + call miiupk16 (Mems[ip], Mems[index], sz_index, TY_SHORT) + PL_NLP(pl) = pl_l2pi (Mems[index], 1, PL_LP(pl,1), nlp) + + # Allocate or resize the line list buffer. + if (PL_LLBP(pl) == NULL) + call malloc (PL_LLBP(pl), PL_LLLEN(pl), TY_SHORT) + else if (PL_LLLEN(pl) != o_lllen) + call realloc (PL_LLBP(pl), PL_LLLEN(pl), TY_SHORT) + + # Read the stored line list. + ip = ip + sz_index + call miiupk16 (Mems[ip], LL(pl,0), PL_LLLEN(pl), TY_SHORT) + + # Update the remaining fields of the mask descriptor. + PL_LLFREE(pl) = 0 + PL_LLNUPDATES(pl) = 0 + PL_LLINC(pl) = PL_STARTINC + call amovki (1, PL_PLANE(pl,1), PL_MAXDIM) + + call sfree (sp) +end diff --git a/sys/plio/plloadf.x b/sys/plio/plloadf.x new file mode 100644 index 00000000..978086b8 --- /dev/null +++ b/sys/plio/plloadf.x @@ -0,0 +1,67 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <plset.h> +include <plio.h> + +# PL_LOADF -- Load a mask stored in external format in a binary file. This +# simple code permits only one mask per file; more sophisticated storage +# facilities are planned; these will probably obsolete this routine. + +procedure pl_loadf (pl, mask, title, maxch) + +pointer pl #I mask descriptor +char mask[ARB] #I mask file +char title[maxch] #O mask title +int maxch #I max chars out + +int fd, nchars +pointer sp, bp, sv, text, fname, extn +int open(), read(), miireadc(), miireadi(), fnextn() +errchk open, read, syserrs +define err_ 91 + +begin + call smark (sp) + call salloc (fname, SZ_PATHNAME, TY_CHAR) + call salloc (extn, SZ_FNAME, TY_CHAR) + + # Get mask file name. + call strcpy (mask, Memc[fname], SZ_PATHNAME) + if (fnextn (mask, Memc[extn], SZ_FNAME) <= 0) + call strcat (".pl", Memc[fname], SZ_PATHNAME) + + # Open the mask save file. + fd = open (Memc[fname], READ_ONLY, BINARY_FILE) + + # Get savefile header. + call salloc (sv, LEN_SVDES, TY_STRUCT) + if (miireadi (fd, Memi[sv], LEN_SVDES) != LEN_SVDES) + goto err_ + + # Verify file type. + if (SV_MAGIC(sv) != PLIO_SVMAGIC) + goto err_ + + # Get descriptive text. + call salloc (text, SV_TITLELEN(sv), TY_CHAR) + if (miireadc (fd, Memc[text], SV_TITLELEN(sv)) != SV_TITLELEN(sv)) + goto err_ + else + call strcpy (Memc[text], title, maxch) + + # Get encoded mask. + call salloc (bp, SV_MASKLEN(sv), TY_SHORT) + iferr (nchars = read (fd, Mems[bp], SV_MASKLEN(sv) * SZ_SHORT)) + goto err_ + call close (fd) + + iferr (call pl_load (pl, bp)) + goto err_ + + call sfree (sp) + return +err_ + call close (fd) + call syserrs (SYS_PLBADSAVEF, Memc[fname]) +end diff --git a/sys/plio/plloadim.x b/sys/plio/plloadim.x new file mode 100644 index 00000000..6fc45adc --- /dev/null +++ b/sys/plio/plloadim.x @@ -0,0 +1,99 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <imhdr.h> +include <imset.h> +include <plset.h> +include <plio.h> + +# PL_LOADIM -- Load a mask stored as a conventional image, i.e., convert an +# image to a mask. + +procedure pl_loadim (pl, imname, title, maxch) + +pointer pl #I mask descriptor +char imname[ARB] #I image name or section +char title[ARB] #O mask title +int maxch #I max chars out + +bool sampling +pointer im, px, im_pl, bp +long vs_l[PL_MAXDIM], vs_p[PL_MAXDIM] +long ve_l[PL_MAXDIM], ve_p[PL_MAXDIM] +int npix, naxes, maxdim, maxval, depth, sz_buf, i +long v_in[PL_MAXDIM], v_out[PL_MAXDIM], vn[PL_MAXDIM] + +pointer immap() +int imgnli(), imstati(), im_pmsvhdr() +errchk immap, imgnli + +begin + # Open the input image. + im = immap (imname, READ_ONLY, 0) + + # Encode and output the image header. + bp = NULL; i = im_pmsvhdr (im, bp, sz_buf) + call strcpy (Memc[bp], title, maxch) + call mfree (bp, TY_CHAR) + + # Determine the mask depth in bits. + maxval = IM_MAX(im) + if (maxval <= 0) + maxval = I_PVMAX + do i = 0, ARB + if (2**i > min (I_PVMAX, maxval)) { + depth = i + break + } + + # Initialize the mask to the size of the image section. + npix = IM_LEN(im,1) + naxes = IM_NDIM(im) + maxdim = min (IM_MAXDIM, PL_MAXDIM) + call amovl (IM_LEN(im,1), vn, maxdim) + call pl_ssize (pl, naxes, vn, depth) + + # If the image is already a mask internally, check whether any + # subsampling, axis flipping, or axis mapping is in effect. + # If so we can't use PLIO to copy the mask section. + + im_pl = imstati (im, IM_PLDES) + sampling = false + + if (im_pl != NULL) { + call amovkl (long(1), vs_l, maxdim) + call amovl (IM_LEN(im,1), ve_l, maxdim) + call imaplv (im, vs_l, vs_p, maxdim) + call imaplv (im, ve_l, ve_p, maxdim) + + do i = 1, maxdim { + vn[i] = ve_l[i] - vs_l[i] + 1 + if (vn[i] != ve_p[i] - vs_p[i] + 1) { + sampling = true + break + } + } + } + + # If the source image is already a mask internally and no axis + # geometry is in effect in the image section (if any), then we can + # use a PLIO rasterop to efficiently copy the mask subsection. + + if (im_pl != NULL && !sampling) { + # Copy a mask subsection (or entire image if no section). + call pl_rop (im_pl, vs_p, pl, vs_l, vn, PIX_SRC) + + } else { + # Copy image pixels. Initialize the vector loop indices. + call amovkl (long(1), v_in, maxdim) + call amovkl (long(1), v_out, maxdim) + + # Copy the image. + while (imgnli (im, px, v_in) != EOF) { + call pl_plpi (pl, v_out, Memi[px], 0, npix, PIX_SRC) + call amovl (v_in, v_out, maxdim) + } + } + + call pl_compress (pl) + call imunmap (im) +end diff --git a/sys/plio/plloop.x b/sys/plio/plloop.x new file mode 100644 index 00000000..500dc8bb --- /dev/null +++ b/sys/plio/plloop.x @@ -0,0 +1,31 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PLLOOP -- Increment the vector V from VS to VE (nested do loops cannot +# be used because of the variable number of dimensions). Return LOOP_DONE +# when V exceeds VE. + +int procedure plloop (v, vs, ve, ndim) + +long v[ndim] #U vector giving current position in image +long vs[ndim] #I start vector +long ve[ndim] #I end vector +int ndim #I vector length + +int i + +begin + do i = 2, ndim { + v[i] = v[i] + 1 + if (v[i] > ve[i]) { + if (i < ndim) + v[i] = vs[i] + else + break + } else + return (LOOP_AGAIN) + } + + return (LOOP_DONE) +end diff --git a/sys/plio/pllpr.x b/sys/plio/pllpr.x new file mode 100644 index 00000000..9a8d1684 --- /dev/null +++ b/sys/plio/pllpr.x @@ -0,0 +1,111 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PLL_PRINTS -- Print a line list on the given output stream. + +procedure pll_prints (ll, fd, label, firstcol, maxcols) + +short ll[ARB] #I line list +int fd #I output file +char label[ARB] #I line label +int firstcol #I first column for output +int maxcols #I width of formatted output + +pointer sp, buf +bool skipword +int opcode, data +int ll_len, ll_first, col, ip, pv, x +int strlen() + +begin + call smark (sp) + call salloc (buf, SZ_FNAME, TY_CHAR) + + # Support old format line lists. + if (LL_OLDFORMAT(ll)) { + ll_len = OLL_LEN(ll) + ll_first = OLL_FIRST + } else { + ll_len = LL_LEN(ll) + ll_first = LL_FIRST(ll) + } + + # Output the line label and advance to the first column. If the label + # extends beyond the first column, start a new line. + + call putline (fd, label) + col = strlen (label) + 1 + if (col > firstcol) + call pl_debugout (fd, "", col, firstcol, maxcols) + + skipword = false + pv = 1 + x = 1 + + # Decode the line list proper. + do ip = ll_first, ll_len { + if (skipword) { + skipword = false + next + } + + opcode = I_OPCODE(ll[ip]) + data = I_DATA(ll[ip]) + + switch (opcode) { + case I_ZN: + x = x + data + call sprintf (Memc[buf], SZ_FNAME, "Z%d") + call pargi (data) + case I_HN: + x = x + data + call sprintf (Memc[buf], SZ_FNAME, "H%d") + call pargi (data) + case I_PN: + x = x + data + call sprintf (Memc[buf], SZ_FNAME, "P%d") + call pargi (data) + + case I_SH: + pv = (int(ll[ip+1]) * I_SHIFT) + data + skipword = true + call sprintf (Memc[buf], SZ_FNAME, "SH(%d)") + call pargi (pv) + case I_IH: + pv = pv + data + call sprintf (Memc[buf], SZ_FNAME, "IH%d(%d)") + call pargi (data) + call pargi (pv) + case I_DH: + pv = pv - data + call sprintf (Memc[buf], SZ_FNAME, "DH%d(%d)") + call pargi (data) + call pargi (pv) + + case I_IS, I_DS: + x = x + 1 + if (opcode == I_IS) { + pv = pv + data + call sprintf (Memc[buf], SZ_FNAME, "IS%d(%d)") + call pargi (data) + call pargi (pv) + } else { + pv = pv - data + call sprintf (Memc[buf], SZ_FNAME, "DS%d(%d)") + call pargi (data) + call pargi (pv) + } + } + + call pl_debugout (fd, Memc[buf], col, firstcol, maxcols) + } + + call sprintf (Memc[buf], SZ_FNAME, "(%d,%d)") + call pargi (x - 1) + call pargi (pv) + call pl_debugout (fd, Memc[buf], col, firstcol, maxcols) + + call pl_debugout (fd, "", col, firstcol, maxcols) + call sfree (sp) +end diff --git a/sys/plio/pllrop.x b/sys/plio/pllrop.x new file mode 100644 index 00000000..2f5f1358 --- /dev/null +++ b/sys/plio/pllrop.x @@ -0,0 +1,271 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include "pllseg.h" +include <plio.h> + +# PL_LINEROP -- Rasterop operation between source and destination line lists. +# The indicated rasterop operation is performed upon the source and destination +# line lists, writing the result to LL_OUT, which is a copy of LL_DST except +# for the region affected by the rasterop operation (note that the destination +# line list cannot be edited in place since it may change size). + +procedure pl_linerop (ll_src, xs, src_maxval, + ll_dst, ds, dst_maxval, ll_out, npix, rop) + +short ll_src[ARB] #I source line list +int xs #I starting pixel index in src line list +int src_maxval #I maximum pixel value, source mask +short ll_dst[ARB] #I destination line list +int ds #I starting pixel index in dst line list +int dst_maxval #I maximum pixel value, dst mask +short ll_out[ARB] #O output list (edited version of ll_dst) +int npix #I number of pixels to convert +int rop #I rasterop + +int segsize, v_src, v_dst, pv +bool need_src, need_dst, rop_enable +int o_op, o_iz, o_pv, o_np, o_hi, src_value +int opcode, data, nz, iz, x1, hi, dv, v, np, op, n, i +int d_src[LEN_PLLDES], d_dst[LEN_PLLDES] +define done_ 91 + +begin + need_src = R_NEED_SRC(rop) + need_dst = R_NEED_DST(rop) + opcode = R_OPCODE(rop) + data = R_DATA(rop) + + # Pixel value to be used if input mask is boolean. + if (src_maxval == 1) { + src_value = data + if (src_value <= 0) + src_value = dst_maxval + } + + # Advance to the desired position in the source list, discarding + # the instructions once read. The point XS may lie within the range + # of an instruction. + + if (need_src) { + x1 = 1 + pll_init (ll_src, d_src) + do i = 1, ARB { + np = min (pll_nleft(d_src), xs - x1) + pll_getseg (ll_src, d_src, np, v_src) + x1 = x1 + np + if (x1 >= xs || np == 0) + break + } + } + + # Copy DST to OUT, applying the rasterop in the region of NPIX pixels + # beginning at DS. To simplify things (avoid pathological complexity + # in this case) we suffer some unnecessary unpacking and repacking + # of encoded line list instructions in the regions of the DST list + # which are simply copied. This avoids the need for special treatment + # at the edges of the region to which the ROP applies. ROP_ENABLE is + # false initially, true in the ROP region, and false again to the + # right. The number of pixels in each region is given by SEGSIZE. + + o_pv = -1 + op = LL_CURHDRLEN + 1 + segsize = ds - 1 + rop_enable = false + x1 = 1; iz = 1; hi = 1 + pll_init (ll_dst, d_dst) + + do i = 1, ARB { + # Set up for the next segment (before, in, and after the region to + # which the ROP applies), when the current segment is exhausted. + + if (segsize <= 0) + if (!rop_enable) { + # Begin processing central region. + segsize = npix + rop_enable = true + if (segsize <= 0) + next + } else { + # Begin processing final region. + segsize = ARB + rop_enable = false + } + + # Determine the length of the next output segment. This is the + # largest segment of constant value formed by the intersection of + # the two lists. If bounds checking has been properly performed + # then it should not be possible to see nleft=zero on either input + # list. Note that zeroed regions are valid data here. + + np = min (segsize, pll_nleft(d_dst)) + if (need_src && rop_enable && pll_nleft(d_src) > 0) + np = min (np, pll_nleft(d_src)) + if (np <= 0) + break + + # Get the segment value and advance the line pointers. We always + # have to read the DST list in order to copy the unmodified regions + # to the output. We read the SRC list and apply the rasterop only + # in the region to which the ROP applies. + + pll_getseg (ll_dst, d_dst, np, v_dst) + if (rop_enable) { + # Get v_src. + if (need_src) { + v_src = 0 + if (pll_nleft (d_src) > 0) + pll_getseg (ll_src, d_src, np, v_src) + + if (R_NOTSRC(rop)) { + v_src = not (v_src) + if (src_maxval != 0) + v_src = and (v_src, src_maxval) + } + + if (v_src != 0 && src_maxval == 1) + v_src = src_value + } + + # Get v_dst. + if (need_dst) { + if (R_NOTDST(rop)) { + v_dst = not (v_dst) + if (dst_maxval != 0) + v_dst = and (v_dst, dst_maxval) + } + } + + # Apply the rasterop. + switch (opcode) { + case PIX_CLR: + pv = 0 + case PIX_SET: + pv = data + case PIX_SRC, PIX_NOTSRC: + pv = v_src + case PIX_DST, PIX_NOTDST: + pv = v_dst + case PIX_SRC_AND_DST, PIX_SRC_AND_NOTDST, PIX_NOTSRC_AND_DST: + pv = and (v_src, v_dst) + case PIX_SRC_OR_DST, PIX_SRC_OR_NOTDST, PIX_NOTSRC_OR_DST: + pv = or (v_src, v_dst) + case PIX_SRC_XOR_DST: + pv = xor (v_src, v_dst) + case PIX_NOT_SRC_AND_DST: + pv = not (and (v_src, v_dst)) + case PIX_NOT_SRC_OR_DST: + pv = not (or (v_src, v_dst)) + case PIX_NOT_SRC_XOR_DST: + pv = not (xor (v_src, v_dst)) + } + + # Mask the high bits to prevent negative values, or map int + # to bool for the case of a boolean output mask. + + if (dst_maxval == 1 && pv != 0) + pv = 1 + else if (dst_maxval > 1) + pv = and (dst_maxval, pv) + + } else + pv = v_dst + + + if (pv == 0) { + if (pll_nleft (d_dst) <= 0) { + # Output zeros at end of list. + x1 = x1 + np + } else { + # Keep going until we get a nonzero range. + o_pv = 0 + x1 = x1 + np + segsize = segsize - np + next + } + } else if (pv == o_pv) { + # Combine with previous range. + iz = o_iz + hi = o_hi + op = o_op + x1 = x1 - o_np + segsize = segsize + o_np + np = np + o_np + o_np = np + } else { + # Save current range parameters. + o_op = op + o_np = np + o_iz = iz + o_hi = hi + o_pv = pv + } + + # Encode an instruction to regenerate the current range of NP data + # values of nonzero level PV, starting at X1. In the most complex + # case we must update the high value and output a range of zeros, + # followed by a range of NP high values. If NP is 1, we can + # probably use a PN or [ID]S instruction to save space. + + nz = x1 - iz + + # Change the high value? + if (pv > 0) { + dv = pv - hi + if (dv != 0) { + # Output IH or DH instruction? + hi = pv + if (abs(dv) > I_DATAMAX) { + ll_out[op] = M_SH + and (pv, I_DATAMAX) + op = op + 1 + ll_out[op] = pv / I_SHIFT + op = op + 1 + } else { + if (dv < 0) + ll_out[op] = M_DH + (-dv) + else + ll_out[op] = M_IH + dv + op = op + 1 + + # Convert to IS or DS if range is a single pixel. + if (np == 1 && nz == 0) { + v = ll_out[op-1] + ll_out[op-1] = or (v, M_MOVE) + goto done_ + } + } + } + } + + # Output range of zeros to catch up to current range? + if (nz > 0) { + # Output the ZN instruction. + for (n=nz; n > 0; n = n - I_DATAMAX) { + ll_out[op] = M_ZN + min(I_DATAMAX,n) + op = op + 1 + } + # Convert to PN if range is a single pixel. + if (np == 1 && pv > 0) { + ll_out[op-1] = ll_out[op-1] + M_PN + 1 + goto done_ + } + # At end of list. + if (pv == 0) + goto done_ + } + + # The only thing left is the HN instruction if we get here. + for (n=np; n > 0; n = n - I_DATAMAX) { + ll_out[op] = M_HN + min(I_DATAMAX,n) + op = op + 1 + } +done_ + segsize = segsize - np + x1 = x1 + np + iz = x1 + } + + # Update the line list header. + call amovs (ll_dst, ll_out, LL_CURHDRLEN) + LL_SETLEN(ll_out, op - 1) +end diff --git a/sys/plio/pllseg.h b/sys/plio/pllseg.h new file mode 100644 index 00000000..2f358944 --- /dev/null +++ b/sys/plio/pllseg.h @@ -0,0 +1,56 @@ +# PLLSEG.H -- Macros for sequentially reading segments of a line list. +# +# pll_init (ll, descriptor) +# npix = pll_nleft (descriptor) +# val = pll_getseg (ll, descriptor, npix, value) +# +# pll_init Initialize descriptor for sequential i/o from the linelist LL. +# pll_nleft Number of pixels left in the current line segment of constant +# value. Zero is returned at the EOL. +# pll_getseg Read NPIX pixels from the current segment, advancing to the +# next segment automatically when the the current segment is +# exhausted. +# +# The descriptor is an integer array, the contents of which are hidden from +# the application using these macros. This package uses the internal +# procedure PLL_NEXTSEG, which is included in PL package library. + +# Range list i/o descriptor. +define LEN_PLLDES 7 +define ld_nleft $1[1] +define ld_value $1[2] +define ld_x $1[3] +define ld_ip $1[4] +define ld_hi $1[5] +define ld_next_nleft $1[6] +define ld_next_value $1[7] + +# PLL_INIT -- Initialize the linelist descriptor. +define (pll_init, { # $1=ll $2=des + # ld_x($2) = 1 + ld_hi($2) = 1 + if (LL_OLDFORMAT($1)) + ld_ip($2) = OLL_FIRST + else + ld_ip($2) = LL_FIRST($1) + ld_next_nleft($2) = 0 + ld_nleft($2) = 0 + call pll_nextseg ($1, $2) +}) + +# PLL_NLEFT -- Number of pixels left in the current segment. +define pll_nleft ld_nleft($1) + +# PLL_GETSEG -- Read pixels from the current segment. +define (pll_getseg, { # $1=ll $2=des $3=npix $4=value + $4 = ld_value($2) + # ld_x($2) = ld_x($2) + $3 + ld_nleft($2) = ld_nleft($2) - $3 + if (ld_nleft($2) <= 0) + if (ld_next_nleft($2) > 0) { + ld_nleft($2) = ld_next_nleft($2) + ld_value($2) = ld_next_value($2) + ld_next_nleft($2) = 0 + } else + call pll_nextseg ($1, $2) +}) diff --git a/sys/plio/pllsten.x b/sys/plio/pllsten.x new file mode 100644 index 00000000..cfd125f3 --- /dev/null +++ b/sys/plio/pllsten.x @@ -0,0 +1,289 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include "pllseg.h" +include <plio.h> + +# PL_LINESTENCIL -- Rasterop operation between source and destination line +# lists, reading the source and applying the rasterop only in the regions +# specified by the stencil line list. The stencil list is aligned with the +# source list. + +procedure pl_linestencil (ll_src,xs,src_maxval, ll_dst,ds,dst_maxval, + ll_stn,ss, ll_out, npix, rop) + +short ll_src[ARB] #I source line list +int xs #I starting pixel index in src line list +int src_maxval #I maximum pixel value, source mask +short ll_dst[ARB] #I destination line list +int ds #I starting pixel index in dst line list +int dst_maxval #I maximum pixel value, destination mask +short ll_stn[ARB] #I stencil line list +int ss #I starting pixel index in stn line list +short ll_out[ARB] #O output list (edited version of ll_dst) +int npix #I number of pixels to convert +int rop #I rasterop + +bool need_src, rop_enable +int o_op, o_iz, o_pv, o_np, o_hi +int segsize, v_src, v_dst, v_stn, pv, src_value +int opcode, data, x1, hi, dv, v, iz, nz, np, op, n, i +int d_src[LEN_PLLDES], d_dst[LEN_PLLDES], d_stn[LEN_PLLDES] +define copyout_ 91 +define done_ 92 + +begin + need_src = R_NEED_SRC(rop) + opcode = R_OPCODE(rop) + data = R_DATA(rop) + + # Pixel value to be used if input mask is boolean. + if (src_maxval == 1) + src_value = data + if (src_value <= 0) + src_value = src_maxval + + # Advance to the indicated position in the source list, discarding + # the instructions once read. The point XS may lie within the range + # of an instruction. + + if (need_src) { + x1 = 1 + pll_init (ll_src, d_src) + do i = 1, ARB { + np = min (pll_nleft(d_src), xs - x1) + pll_getseg (ll_src, d_src, np, v_src) + x1 = x1 + np + if (x1 >= xs || np == 0) + break + } + } + + # Advance to the indicated position in the stencil list. This causes + # the point SS in the stencil to be aligned with the point XS in the + # source. + + if (need_src) { + x1 = 1 + pll_init (ll_stn, d_stn) + do i = 1, ARB { + np = min (pll_nleft(d_stn), xs - x1) + pll_getseg (ll_stn, d_stn, np, v_stn) + x1 = x1 + np + if (x1 >= xs || np == 0) + break + } + } + + # Copy DST to OUT, applying the rasterop in the region of NPIX pixels + # beginning at DS. To simplify things (avoid pathological complexity + # in this case) we suffer some unnecessary unpacking and repacking + # of encoded line list instructions in the regions of the DST list + # which are simply copied. This avoids the need for special treatment + # at the edges of the region to which the ROP applies. ROP_ENABLE is + # false initially, true in the ROP region, and false again to the + # right. The number of pixels in each region is given by SEGSIZE. + + o_pv = -1 + op = LL_CURHDRLEN + 1 + segsize = ds - 1 + rop_enable = false + x1 = 1; iz = 1; hi = 1 + pll_init (ll_dst, d_dst) + + do i = 1, ARB { + # Set up for the next segment (before, in, and after the region to + # which the ROP applies), when the current segment is exhausted. + + if (segsize <= 0) + if (!rop_enable) { + # Begin processing central region. + segsize = npix + rop_enable = true + if (segsize <= 0) + next + } else { + # Begin processing final region. + segsize = ARB + rop_enable = false + } + + # Determine the length of the next output segment. This is the + # largest segment of constant value formed by the intersection of + # the two lists. If bounds checking has been performed properly + # then it should not be possible to see nleft=zero on either input + # list. Note that zeroed regions are valid data here. + + np = min (segsize, pll_nleft(d_dst)) + if (need_src && rop_enable && pll_nleft(d_src) > 0) { + np = min (np, pll_nleft(d_src)) + if (pll_nleft (d_stn) > 0) + np = min (np, pll_nleft(d_stn)) + } + if (np <= 0) + break + + # Get the segment value and advance the line pointers. We always + # have to read the DST list to copy it to the output. We read the + # SRC list and apply the rasterop only in the region to which the + # ROP applies. + + pll_getseg (ll_dst, d_dst, np, v_dst) + if (rop_enable) { + if (need_src) { + v_src = 0 + if (pll_nleft (d_src) > 0) + pll_getseg (ll_src, d_src, np, v_src) + if (v_src != 0 && src_maxval == 1) + v_src = src_value + pll_getseg (ll_stn, d_stn, np, v_stn) + if (v_stn == 0) + goto copyout_ + } + + # Compute the pixel value for the new output segment, given the + # source and destination pixel values and the rasterop supplied. + + switch (opcode) { + case PIX_CLR: + pv = 0 + case PIX_SET: + pv = data + case PIX_SRC: + pv = v_src + case PIX_DST: + pv = v_dst + case PIX_NOTSRC: + pv = not (v_src) + case PIX_NOTDST: + pv = not (v_dst) + case PIX_SRC_AND_DST: + pv = and (v_src, v_dst) + case PIX_SRC_OR_DST: + pv = or (v_src, v_dst) + case PIX_SRC_XOR_DST: + pv = xor (v_src, v_dst) + case PIX_SRC_AND_NOTDST: + pv = and (v_src, not(v_dst)) + case PIX_SRC_OR_NOTDST: + pv = or (v_src, not(v_dst)) + case PIX_NOTSRC_AND_DST: + pv = and (not(v_src), v_dst) + case PIX_NOTSRC_OR_DST: + pv = or (not(v_src), v_dst) + case PIX_NOT_SRC_AND_DST: + pv = not (and (v_src, v_dst)) + case PIX_NOT_SRC_OR_DST: + pv = not (or (v_src, v_dst)) + case PIX_NOT_SRC_XOR_DST: + pv = not (xor (v_src, v_dst)) + } + + # Mask the high bits to prevent negative values, handle the + # case of a boolean output mask. + + if (dst_maxval == 1 && pv != 0) + pv = 1 + else if (dst_maxval > 1) + pv = and (dst_maxval, pv) + + } else +copyout_ pv = v_dst + + if (pv == 0) { + if (pll_nleft (d_dst) <= 0) { + # Output zeros at end of list. + x1 = x1 + np + } else { + # Keep going until we get a nonzero range. + o_pv = 0 + x1 = x1 + np + segsize = segsize - np + next + } + } else if (pv == o_pv) { + # Combine with previous range. + iz = o_iz + hi = o_hi + op = o_op + x1 = x1 - o_np + segsize = segsize + o_np + np = np + o_np + o_np = np + } else { + # Save current range parameters. + o_op = op + o_np = np + o_iz = iz + o_hi = hi + o_pv = pv + } + + # Encode an instruction to regenerate the current range of NP data + # values of nonzero level PV, starting at X1. In the most complex + # case we must update the high value and output a range of zeros, + # followed by a range of NP high values. If NP is 1, we can + # probably use a PN or [ID]S instruction to save space. + + nz = x1 - iz + + # Change the high value? + if (pv > 0) { + dv = pv - hi + if (dv != 0) { + # Output IH or DH instruction? + hi = pv + if (abs(dv) > I_DATAMAX) { + ll_out[op] = M_SH + and (pv, I_DATAMAX) + op = op + 1 + ll_out[op] = pv / I_SHIFT + op = op + 1 + } else { + if (dv < 0) + ll_out[op] = M_DH + (-dv) + else + ll_out[op] = M_IH + dv + op = op + 1 + + # Convert to IS or DS if range is a single pixel. + if (np == 1 && nz == 0) { + v = ll_out[op-1] + ll_out[op-1] = or (v, M_MOVE) + goto done_ + } + } + } + } + + # Output range of zeros to catch up to current range? + if (nz > 0) { + # Output the ZN instruction. + for (n=nz; n > 0; n = n - I_DATAMAX) { + ll_out[op] = M_ZN + min(I_DATAMAX,n) + op = op + 1 + } + # Convert to PN if range is a single pixel. + if (np == 1 && pv > 0) { + ll_out[op-1] = ll_out[op-1] + M_PN + 1 + goto done_ + } + # At end of list. + if (pv == 0) + goto done_ + } + + # The only thing left is the HN instruction if we get here. + for (n=np; n > 0; n = n - I_DATAMAX) { + ll_out[op] = M_HN + min(I_DATAMAX,n) + op = op + 1 + } +done_ + segsize = segsize - np + x1 = x1 + np + iz = x1 + } + + # Update the line list header. + call amovs (ll_dst, ll_out, LL_CURHDRLEN) + LL_SETLEN(ll_out, op - 1) +end diff --git a/sys/plio/plnewcopy.x b/sys/plio/plnewcopy.x new file mode 100644 index 00000000..a429bc6e --- /dev/null +++ b/sys/plio/plnewcopy.x @@ -0,0 +1,30 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_NEWCOPY -- Create a new, empty mask with the same size and depth +# attributes as the reference mask. + +pointer procedure pl_newcopy (old_pl) + +pointer old_pl #I mask descriptor + +pointer new_pl +int naxes, depth +long axlen[PL_MAXDIM] +pointer pl_open() +errchk pl_open + +begin + new_pl = pl_open (NULL) + + call pl_gsize (old_pl, naxes, axlen, depth) + call pl_ssize (new_pl, naxes, axlen, depth) + + PL_PRIVATE1(new_pl) = PL_PRIVATE1(old_pl) + PL_PRIVATE2(new_pl) = PL_PRIVATE2(old_pl) + PL_MAXLINE(new_pl) = PL_MAXLINE(old_pl) + + return (new_pl) +end diff --git a/sys/plio/plopen.x b/sys/plio/plopen.x new file mode 100644 index 00000000..6510ebe5 --- /dev/null +++ b/sys/plio/plopen.x @@ -0,0 +1,30 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_OPEN -- Open a mask. If the input buffer pointer is NULL an inactive +# mask descriptor is allocated, otherwise the pointer is taken to point to +# an encoded mask, which is decoded and loaded to create an active descriptor. + +pointer procedure pl_open (smp) + +pointer smp #I stored mask pointer or NULL + +pointer pl +errchk calloc, pl_load + +begin + # Allocate and initialize an inactive descriptor. + call calloc (pl, LEN_PLDES, TY_STRUCT) + + call amovki (1, PL_PLANE(pl,1), PL_MAXDIM) + PL_MAGIC(pl) = PL_MAGICVAL + PL_LLINC(pl) = PL_STARTINC + + # Load the saved mask, if any. + if (smp != NULL) + call pl_load (pl, smp) + + return (pl) +end diff --git a/sys/plio/plp2l.gx b/sys/plio/plp2l.gx new file mode 100644 index 00000000..85a59507 --- /dev/null +++ b/sys/plio/plp2l.gx @@ -0,0 +1,126 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_P2L -- Convert a pixel array to a line list. The length of the list is +# returned as the function value. + +int procedure pl_p2l$t (px_src, xs, ll_dst, npix) + +PIXEL px_src[ARB] #I input pixel array +int xs #I starting index in pixbuf +short ll_dst[ARB] #O destination line list +int npix #I number of pixels to convert + +PIXEL hi, pv, nv, zero +int xe, x1, iz, ip, op, np, nz, dv, v +define done_ 91 + +begin + # No input pixels? + if (npix <= 0) + return (0) + + # Initialize the linelist header. + LL_VERSION(ll_dst) = LL_CURVERSION + LL_HDRLEN(ll_dst) = LL_CURHDRLEN + LL_NREFS(ll_dst) = 0 + LL_SETBLEN(ll_dst,0) + + xe = xs + npix - 1 + op = LL_CURHDRLEN + 1 + + # Pack the pixel array into a line list. This is done by scanning + # the pixel list for successive ranges of pixels of constant nonzero + # value, where each range is described as follows: + + zero = 0 + pv = max (zero, px_src[xs]) # pixel value of current range + x1 = xs # start index of current range + iz = xs # start index of range of zeros + hi = 1 # current high value + + # Process the data array. + do ip = xs, xe { + if (ip < xe) { + # Get the next pixel value, loop again if same as previous one. + nv = max (zero, px_src[ip+1]) + if (nv == pv) + next + + # If current range is zero, loop again to get nonzero range. + if (pv == 0) { + pv = nv + x1 = ip + 1 + next + } + } else if (pv == 0) + x1 = xe + 1 + + # Encode an instruction to regenerate the current range I0-IP + # of N data values of nonzero level PV. In the most complex case + # we must update the high value and output a range of zeros, + # followed by a range of NP high values. If NP is 1, we can + # probably use a PN or [ID]S instruction to save space. + + np = ip - x1 + 1 + nz = x1 - iz + + # Change the high value? + if (pv > 0) { + dv = pv - hi + if (dv != 0) { + # Output IH or DH instruction? + hi = pv + if (abs(dv) > I_DATAMAX) { + ll_dst[op] = M_SH + and (int(pv), I_DATAMAX) + op = op + 1 + ll_dst[op] = pv / I_SHIFT + op = op + 1 + } else { + if (dv < 0) + ll_dst[op] = M_DH + (-dv) + else + ll_dst[op] = M_IH + dv + op = op + 1 + + # Convert to IS or DS if range is a single pixel. + if (np == 1 && nz == 0) { + v = ll_dst[op-1] + ll_dst[op-1] = or (v, M_MOVE) + goto done_ + } + } + } + } + + # Output range of zeros to catch up to current range? + # The I_DATAMAX-1 limit is to allow adding M_PN+1 without + # overflowing the range of the data segment. + if (nz > 0) { + # Output the ZN instruction. + for (; nz > 0; nz = nz - (I_DATAMAX-1)) { + ll_dst[op] = M_ZN + min(I_DATAMAX-1,nz) + op = op + 1 + } + # Convert to PN if range is a single pixel. + if (np == 1 && pv > 0) { + ll_dst[op-1] = ll_dst[op-1] + M_PN + 1 + goto done_ + } + } + + # The only thing left is the HN instruction if we get here. + for (; np > 0; np = np - I_DATAMAX) { + ll_dst[op] = M_HN + min(I_DATAMAX,np) + op = op + 1 + } +done_ + x1 = ip + 1 + iz = x1 + pv = nv + } + + LL_SETLEN(ll_dst, op - 1) + return (op - 1) +end diff --git a/sys/plio/plp2r.gx b/sys/plio/plp2r.gx new file mode 100644 index 00000000..2e1d1984 --- /dev/null +++ b/sys/plio/plp2r.gx @@ -0,0 +1,71 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_P2R -- Convert a pixel array to a range list. The length of the output +# range list is returned as the function value. + +int procedure pl_p2r$t (px_src, xs, rl, npix) + +PIXEL px_src[ARB] #I input pixel array +int xs #I starting index in pixbuf +PIXEL rl[3,ARB] #O destination range list +int npix #I number of pixels to convert + +PIXEL hi, pv, zero +int xe, x1, np, rn, nv, ip +define done_ 91 + +begin + # No input pixels? + if (npix <= 0) + return (0) + + xe = xs + npix - 1 + rn = RL_FIRST + + # Pack the pixel array into a range list. This is done by scanning + # the pixel list for successive ranges of pixels of constant nonzero + # value, where each range is described as follows: + + zero = 0 + pv = max (zero, px_src[xs]) # pixel value of current range + x1 = xs # start index of current range + hi = 1 # current high value + + # Process the data array. + do ip = xs, xe { + if (ip < xe) { + # Get the next pixel value, loop again if same as previous one. + nv = max (zero, px_src[ip+1]) + if (nv == pv) + next + + # If current range is zero, loop again to get nonzero range. + if (pv == 0) { + pv = nv + x1 = ip + 1 + next + } + } + + np = ip - x1 + 1 + + # Output the new range. + if (pv > 0) { + rl[1,rn] = x1 + rl[2,rn] = np + rl[3,rn] = pv + rn = rn + 1 + } + + x1 = ip + 1 + pv = nv + } + + RL_LEN(rl) = rn - 1 + RL_AXLEN(rl) = npix + + return (rn - 1) +end diff --git a/sys/plio/plplls.x b/sys/plio/plplls.x new file mode 100644 index 00000000..8f8ca491 --- /dev/null +++ b/sys/plio/plplls.x @@ -0,0 +1,35 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_PLLS -- Put a line segment input as a line list to a mask, applying the +# given ROP to combine the line segment with the existing line of the mask. + +procedure pl_plls (pl, v, ll_src, ll_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +short ll_src[ARB] #I input line list +int ll_depth #I line list depth, bits +int npix #I number of pixels to be set +int rop #I rasterop + +pointer sp, ll_out, ll_dst +pointer pl_access() +errchk pl_access + +begin + if (!R_NEED_DST(rop) && v[1] == 1 && npix == PL_AXLEN(pl,1)) + call pl_update (pl, v, ll_src) + else { + call smark (sp) + call salloc (ll_out, LL_MAXLEN(pl), TY_SHORT) + + ll_dst = pl_access (pl,v) + call pl_linerop (ll_src, 1, PL_MAXVAL(pl), Mems[ll_dst], v[1], + MV(ll_depth), Mems[ll_out], npix, rop) + call pl_update (pl, v, Mems[ll_out]) + + call sfree (sp) + } +end diff --git a/sys/plio/plplp.gx b/sys/plio/plplp.gx new file mode 100644 index 00000000..01a3596c --- /dev/null +++ b/sys/plio/plplp.gx @@ -0,0 +1,41 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_PLP -- Put a line segment input as a pixel array to a mask, applying the +# given ROP to combine the line segment with the existing line of the mask. + +procedure pl_plp$t (pl, v, px_src, px_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +PIXEL px_src[ARB] #I input pixel array +int px_depth #I pixel depth, bits +int npix #I number of pixels to be set +int rop #I rasterop + +int ll_len +pointer sp, ll_src, ll_out, ll_dst +pointer pl_access() +int pl_p2l$t() +errchk pl_access + +begin + call smark (sp) + call salloc (ll_src, LL_MAXLEN(pl), TY_SHORT) + + # Convert the pixel array to a line list. + ll_len = pl_p2l$t (px_src, 1, Mems[ll_src], npix) + + if (!R_NEED_DST(rop) && v[1] == 1 && npix == PL_AXLEN(pl,1)) + call pl_update (pl, v, Mems[ll_src]) + else { + call salloc (ll_out, LL_MAXLEN(pl), TY_SHORT) + ll_dst = pl_access (pl,v) + call pl_linerop (Mems[ll_src], 1, PL_MAXVAL(pl), Mems[ll_dst], v[1], + MV(px_depth), Mems[ll_out], npix, rop) + call pl_update (pl, v, Mems[ll_out]) + } + + call sfree (sp) +end diff --git a/sys/plio/plplr.gx b/sys/plio/plplr.gx new file mode 100644 index 00000000..d33ba40c --- /dev/null +++ b/sys/plio/plplr.gx @@ -0,0 +1,41 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_PLR -- Put a line segment input as a range list to a mask, applying the +# given ROP to combine the line segment with the existing line of the mask. + +procedure pl_plr$t (pl, v, rl_src, rl_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +PIXEL rl_src[ARB] #I input range list +int rl_depth #I range list depth, bits +int npix #I number of pixels to be set +int rop #I rasterop + +int ll_len +pointer sp, ll_src, ll_out, ll_dst +pointer pl_access() +int pl_r2l$t() +errchk pl_access + +begin + call smark (sp) + call salloc (ll_src, LL_MAXLEN(pl), TY_SHORT) + + # Convert the range list to a line list. + ll_len = pl_r2l$t (rl_src, 1, Mems[ll_src], npix) + + if (!R_NEED_DST(rop) && v[1] == 1 && npix == PL_AXLEN(pl,1)) + call pl_update (pl, v, Mems[ll_src]) + else { + call salloc (ll_out, LL_MAXLEN(pl), TY_SHORT) + ll_dst = pl_access (pl,v) + call pl_linerop (Mems[ll_src], 1, PL_MAXVAL(pl), Mems[ll_dst], v[1], + MV(rl_depth), Mems[ll_out], npix, rop) + call pl_update (pl, v, Mems[ll_out]) + } + + call sfree (sp) +end diff --git a/sys/plio/plpoint.x b/sys/plio/plpoint.x new file mode 100644 index 00000000..de9b7ede --- /dev/null +++ b/sys/plio/plpoint.x @@ -0,0 +1,62 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_POINT -- Perform a rasterop operation on a single point in a line of a +# 2-dimensional plane of a mask. If the dimensionality of the mask exceeds 2, +# the pl_setplane() procedure should be called first to define the plane of +# the mask to be modified. + +procedure pl_point (pl, x, y, rop) + +pointer pl #I mask descriptor +int x #I pixel to be modified +int y #I line to be modified +int rop #I rasterop defining operation + +long v[PL_MAXDIM] +int npix, ll_len +pointer sp, ll_out, ll_reg, rl_out, ll_dst, op +errchk plvalid, pl_access, pl_linerop, pl_update +pointer pl_access() +int pl_r2li() + +begin + call plvalid (pl) + call amovl (PL_PLANE(pl,1), v, PL_MAXDIM) + v[2] = y + + call smark (sp) + call salloc (ll_out, LL_MAXLEN(pl), TY_SHORT) + call salloc (ll_reg, LL_CURHDRLEN + 6, TY_SHORT) + call salloc (rl_out, RL_FIRST * 3, TY_INT) + + # Access the destination line in the mask. + ll_dst = pl_access (pl, v) + + # Construct the edit-region list. + npix = 1 + RLI_AXLEN(rl_out) = npix + RLI_LEN(rl_out) = RL_FIRST + + op = rl_out + (RL_FIRST - 1) * 3 + Memi[op+RL_XOFF] = 1 + Memi[op+RL_NOFF] = npix + Memi[op+RL_VOFF] = 1 + + ll_len = pl_r2li (Memi[rl_out], 1, Mems[ll_reg], npix) + + # Edit the affected line. + call pl_linerop (Mems[ll_reg], 1, 1, Mems[ll_dst], x, PL_MAXVAL(pl), + Mems[ll_out], npix, rop) + + # Update the edited line in the mask. + call pl_update (pl, v, Mems[ll_out]) + + # Compress the mask if excessive free space has accumulated. + if (PL_NEEDCOMPRESS(pl)) + call pl_compress (pl) + + call sfree (sp) +end diff --git a/sys/plio/plpolygon.h b/sys/plio/plpolygon.h new file mode 100644 index 00000000..764b32ae --- /dev/null +++ b/sys/plio/plpolygon.h @@ -0,0 +1,16 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + + +define TOL 0.0001 # pixel units +define swapi {tempi=$2;$2=$1;$1=tempi} +define swapr {tempr=$2;$2=$1;$1=tempr} +define equal (abs($1-$2)<TOL) + +define LEN_PGONDES 7 +define P_PL Memi[$1] # pointer to X vector +define P_XP Memi[$1+1] # pointer to X vector +define P_YP Memi[$1+2] # pointer to Y vector +define P_OO Memi[$1+3] # pointer to previous range list +define P_OY Memi[$1+4] # y value of previous range list +define P_NS Memi[$1+5] # number of line segments +define P_PV Memi[$1+6] # pixel value diff --git a/sys/plio/plpolygon.x b/sys/plio/plpolygon.x new file mode 100644 index 00000000..dc249b88 --- /dev/null +++ b/sys/plio/plpolygon.x @@ -0,0 +1,71 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> +include "plpolygon.h" + + +# PL_POLYGON -- Perform a rasterop operation on the area enclosed by a polygon +# drawn in a 2-dimensional plane of a mask. If the dimensionality of the mask +# exceeds 2, the pl_setplane() procedure should be called first to define the +# plane of the mask to be modified. + +procedure pl_polygon (pl, x, y, npts, rop) + +pointer pl #I mask descriptor +int x[npts] #I polygon x-vertices +int y[npts] #I polygon y-vertices +int npts #I number of points in polygon +int rop #I rasterop defining operation + +int line_1, line_2, i +pointer sp, ufd, xp, yp, oo +extern pl_upolygon() +errchk plvalid + +begin + call plvalid (pl) + if (npts <= 0) + return + else if (npts == 1) { + call pl_point (pl, x[1], y[1], rop) + return + } + + call smark (sp) + call salloc (ufd, LEN_PGONDES, TY_STRUCT) + call salloc (oo, RL_FIRST + (npts+1)*3, TY_INT) + call salloc (xp, npts + 1, TY_REAL) + call salloc (yp, npts + 1, TY_REAL) + + # Initialize the region descriptor. + P_PL(ufd) = pl + P_XP(ufd) = xp + P_YP(ufd) = yp + P_PV(ufd) = 1 + P_OO(ufd) = oo + P_OY(ufd) = -1 + P_NS(ufd) = npts - 1 + RLI_LEN(oo) = 0 + + # Copy the user supplied polygon vertices into the descriptor, + # normalizing the polygon in the process. + + do i = 1, npts { + Memr[xp+i-1] = x[i] + Memr[yp+i-1] = y[i] + } + + if (npts > 2) + if (abs(x[1]-x[npts]) > TOL || abs(y[1]-y[npts]) > TOL) { + Memr[xp+npts] = x[1] + Memr[yp+npts] = y[1] + P_NS(ufd) = npts + } + + # Compute the range in Y in which the polygon should be drawn. + call alimi (y, npts, line_1, line_2) + + call pl_regionrop (pl, pl_upolygon, ufd, line_1, line_2, rop) + call sfree (sp) +end diff --git a/sys/plio/plprop.gx b/sys/plio/plprop.gx new file mode 100644 index 00000000..60d1c603 --- /dev/null +++ b/sys/plio/plprop.gx @@ -0,0 +1,177 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_PIXROP -- Rasterop between source and destination pixel arrays. + +procedure pl_pixrop$t (px_src,xs,src_maxval, px_dst,ds,dst_maxval, npix, rop) + +PIXEL px_src[ARB] #I source pixel array +int xs #I starting pixel index in src +int src_maxval #I max pixel value in src mask +PIXEL px_dst[ARB] #O destination pixel array +int ds #I starting pixel index in dst +int dst_maxval #I max pixel value in dst mask +int npix #I number of pixels to convert +int rop #I rasterop + +pointer sp, src +int opcode, i +PIXEL data, ceil, src_value +int and(), or(), xor(), not() +define out_ 91 + +begin + opcode = R_OPCODE(rop) + data = R_DATA(rop) + ceil = 0 + + # Pixel value to be used if input mask is boolean. + if (src_maxval == 1) { + src_value = data + if (src_value <= 0) + src_value = dst_maxval + } + + # Handle the easy cases first. + switch (opcode) { + case PIX_CLR: + call aclr$t (px_dst[ds], npix) + return + case PIX_SET: + call amovk$t (data, px_dst[ds], npix) + goto out_ + case PIX_SRC: + if (src_maxval != 1) + call amov$t (px_src[xs], px_dst[ds], npix) + else { + do i = 1, npix + if (px_src[xs+i-1] > 0) + px_dst[ds+i-1] = src_value + else + px_dst[ds+i-1] = 0 + } + + goto out_ + case PIX_DST: + return # no-op + } + + # Integer or boolean source mask? + if (src_maxval != 1) { + # Integer source mask; operate directly on source mask. + + switch (opcode) { + case PIX_NOTSRC: + do i = 1, npix + px_dst[ds+i-1] = not (px_src[xs+i-1]) + case PIX_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = not (px_dst[xs+i-1]) + + case PIX_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (px_src[xs+i-1], px_dst[ds+i-1]) + case PIX_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (px_src[xs+i-1], px_dst[ds+i-1]) + case PIX_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = xor (px_src[xs+i-1], px_dst[ds+i-1]) + + case PIX_SRC_AND_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = and (px_src[xs+i-1], not(px_dst[ds+i-1])) + case PIX_SRC_OR_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = or (px_src[xs+i-1], not(px_dst[ds+i-1])) + case PIX_NOTSRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (not(px_src[xs+i-1]), px_dst[ds+i-1]) + case PIX_NOTSRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (not(px_src[xs+i-1]), px_dst[ds+i-1]) + + case PIX_NOT_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = not (and (px_src[xs+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = not ( or (px_src[xs+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = not (xor (px_src[xs+i-1], px_dst[ds+i-1])) + } + + } else { + # Boolean source mask; use integer DATA value from ROP if source + # mask pixel is set. + + call smark (sp) + call salloc (src, npix, TY_PIXEL) + + do i = 1, npix + if (px_src[xs+i-1] > 0) + Mem$t[src+i-1] = src_value + else + Mem$t[src+i-1] = 0 + + switch (opcode) { + case PIX_NOTSRC: + do i = 1, npix + px_dst[ds+i-1] = not (Mem$t[src+i-1]) + case PIX_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = not (px_dst[xs+i-1]) + + case PIX_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (Mem$t[src+i-1], px_dst[ds+i-1]) + case PIX_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (Mem$t[src+i-1], px_dst[ds+i-1]) + case PIX_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = xor (Mem$t[src+i-1], px_dst[ds+i-1]) + + case PIX_SRC_AND_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = and (Mem$t[src+i-1], not(px_dst[ds+i-1])) + case PIX_SRC_OR_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = or (Mem$t[src+i-1], not(px_dst[ds+i-1])) + case PIX_NOTSRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (not(Mem$t[src+i-1]), px_dst[ds+i-1]) + case PIX_NOTSRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (not(Mem$t[src+i-1]), px_dst[ds+i-1]) + + case PIX_NOT_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = not (and (Mem$t[src+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = not ( or (Mem$t[src+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = not (xor (Mem$t[src+i-1], px_dst[ds+i-1])) + } + + call sfree (sp) + } +out_ + # If writing to an integer mask, mask the data to the indicated max + # value (necessary to avoid very large values if any NOT operations + # occurred). If writing to a boolean mask, map positive integer mask + # values to 1. + + if (dst_maxval == 1) { + data = 1 + call argt$t (px_dst[ds], npix, ceil, data) + } else if (dst_maxval > 1) { + data = dst_maxval + call aandk$t (px_dst[ds], data, px_dst[ds], npix) + } +end diff --git a/sys/plio/plr2l.gx b/sys/plio/plr2l.gx new file mode 100644 index 00000000..d0a98e92 --- /dev/null +++ b/sys/plio/plr2l.gx @@ -0,0 +1,130 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_R2L -- Convert a range list to a line list. The length of the output +# line list is returned as the function value. + +int procedure pl_r2l$t (rl_src, xs, ll_dst, npix) + +PIXEL rl_src[3,ARB] #I input range list +int xs #I starting pixel index in range list +short ll_dst[ARB] #O destination line list +int npix #I number of pixels to convert + +PIXEL hi, pv +int last, xe, x1, x2, iz, op, np, nz, nr, dv, v, i +define done_ 91 + +begin + # No input pixels? + nr = RL_LEN(rl_src) + if (npix <= 0 || nr <= 0) + return (0) + + # Initialize the linelist header. + LL_VERSION(ll_dst) = LL_CURVERSION + LL_HDRLEN(ll_dst) = LL_CURHDRLEN + LL_NREFS(ll_dst) = 0 + LL_SETBLEN(ll_dst,0) + + xe = xs + npix - 1 + op = LL_CURHDRLEN + 1 + iz = xs + hi = 1 + + # Process the array of range lists. + do i = RL_FIRST, nr + 1 { + if (i <= nr) { + # Load next range. + x1 = rl_src[1,i] + np = rl_src[2,i] + pv = rl_src[3,i] + x2 = x1 + np - 1 + last = x2 + + # Get an inbounds range. + if (x1 > xe) + break + else if (xs > x2) + next + else if (x1 < xs) + x1 = xs + else if (x2 > xe) + x2 = xe + + # Go again if nothing inbounds. + nz = x1 - iz + np = x2 - x1 + 1 + if (np <= 0) + next + + } else if (iz < xe) { + # At end of input range list, but need to output a ZN. + nz = xe - iz + 1 + np = 0 + pv = 0 + } else + break + + # Encode an instruction to regenerate the current range I0-IP + # of N data values of nonzero level PV. In the most complex case + # we must update the high value and output a range of zeros, + # followed by a range of NP high values. If NP is 1, we can + # probably use a PN or [ID]S instruction to save space. + + # Change the high value? + if (pv > 0) { + dv = pv - hi + if (dv != 0) { + # Output IH or DH instruction? + hi = pv + if (abs(dv) > I_DATAMAX) { + ll_dst[op] = M_SH + and (int(pv), I_DATAMAX) + op = op + 1 + ll_dst[op] = pv / I_SHIFT + op = op + 1 + } else { + if (dv < 0) + ll_dst[op] = M_DH + (-dv) + else + ll_dst[op] = M_IH + dv + op = op + 1 + + # Convert to IS or DS if range is a single pixel. + if (np == 1 && nz == 0) { + v = ll_dst[op-1] + ll_dst[op-1] = or (v, M_MOVE) + goto done_ + } + } + } + } + + # Output range of zeros to catch up to current range? + if (nz > 0) { + # Output the ZN instruction. + for (; nz > 0; nz = nz - (I_DATAMAX-1)) { + ll_dst[op] = M_ZN + min(I_DATAMAX-1,nz) + op = op + 1 + } + # Convert to PN if range is a single pixel. + if (np == 1 && pv > 0 && x2 == last) { + ll_dst[op-1] = ll_dst[op-1] + M_PN + 1 + goto done_ + } + } + + # The only thing left is the HN instruction if we get here. + for (; np > 0; np = np - I_DATAMAX) { + ll_dst[op] = M_HN + min(I_DATAMAX,np) + op = op + 1 + } +done_ + iz = x2 + 1 + } + + LL_SETLEN(ll_dst, op - 1) + return (op - 1) +end diff --git a/sys/plio/plr2p.gx b/sys/plio/plr2p.gx new file mode 100644 index 00000000..fa0eecda --- /dev/null +++ b/sys/plio/plr2p.gx @@ -0,0 +1,74 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_R2P -- Convert a range list to a pixel array. The number of pixels +# output (always npix) is returned as the function value. + +int procedure pl_r2p$t (rl_src, xs, px_dst, npix) + +PIXEL rl_src[3,ARB] #I input range list +int xs #I starting pixel index in range list +PIXEL px_dst[ARB] #O output pixel array +int npix #I number of pixels to convert + +PIXEL hi, pv +int xe, x1, x2, iz, op, np, nz, nr, i, j +define done_ 91 + +begin + # No input pixels? + nr = RL_LEN(rl_src) + if (npix <= 0 || nr <= 0) + return (0) + + xe = xs + npix - 1 + iz = xs + op = 1 + hi = 1 + + # Process the array of range lists. + do i = RL_FIRST, nr { + x1 = rl_src[1,i] + np = rl_src[2,i] + pv = rl_src[3,i] + x2 = x1 + np - 1 + + # Get an inbounds range. + if (x1 > xe) + break + else if (xs > x2) + next + else if (x1 < xs) + x1 = xs + else if (x2 > xe) + x2 = xe + + nz = x1 - iz + np = x2 - x1 + 1 + if (np <= 0) + next + + # Output range of zeros to catch up to current range? + if (nz > 0) { + do j = 1, nz + px_dst[op+j-1] = 0 + op = op + nz + } + + # Output the pixels. + do j = 1, np + px_dst[op+j-1] = pv + op = op + np +done_ + x1 = x2 + 1 + iz = x1 + } + + # Zero any remaining output range. + do i = op, npix + px_dst[i] = 0 + + return (npix) +end diff --git a/sys/plio/plregrop.x b/sys/plio/plregrop.x new file mode 100644 index 00000000..6e37183a --- /dev/null +++ b/sys/plio/plregrop.x @@ -0,0 +1,76 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_REGIONROP -- Perform a rasterop operation on an irregular region in a +# 2-dimensional plane of a mask. The boundary of the region is defined by +# a user supplied function which, given the line number (Y) returns a range +# list defining the region for that line. +# +# rl_new = ufcn (ufd, y, rl_out, xs, npix) +# +# where +# rl_new = true if range list for line Y is different than for Y-1 +# ufd = user region descriptor (parameters defining region) +# y = input y value +# rl_out = output range list +# xs = first pixel to be edited in dst mask +# npix = number of pixels in edit region +# +# If the dimensionality of the mask exceeds 2, the pl_setplane() procedure +# should be called first to define the plane of the mask to be modified. + +procedure pl_regionrop (pl, ufcn, ufd, y1, y2, rop) + +pointer pl #I mask descriptor +extern ufcn() #I user supplied region tracing procedure +pointer ufd #I user region descriptor +int y1 #I first mask line to be modified +int y2 #I last mask line to be modified +int rop #I rasterop defining operation + +bool rl_new +long v[PL_MAXDIM] +int ll_len, xs, npix +pointer sp, ll_out, ll_reg, ll_dst, ol_dst, rl_out +pointer pl_access() +int pl_r2li() +bool ufcn() +errchk plvalid + +begin + call plvalid (pl) + + call smark (sp) + call salloc (ll_out, LL_MAXLEN(pl), TY_SHORT) + call salloc (ll_reg, LL_MAXLEN(pl), TY_SHORT) + call salloc (rl_out, RL_MAXLEN(pl), TY_INT) + + call amovl (PL_PLANE(pl,1), v, PL_MAXDIM) + ol_dst = 1 + + for (v[2]=y1; v[2] <= y2; v[2]=v[2]+1) { + ll_dst = pl_access (pl, v) + rl_new = ufcn (ufd, v[2], Memi[rl_out], xs, npix) + if (rl_new) + ll_len = pl_r2li (Memi[rl_out], 1, Mems[ll_reg], npix) + + if (ll_dst != ol_dst || rl_new) { + call pl_linestencil (Mems[ll_reg], 1, 1, + Mems[ll_dst], xs, PL_MAXVAL(pl), + Mems[ll_reg], 1, + Mems[ll_out], npix, rop) + ol_dst = ll_dst + } + + # Update the affected line of the destination mask. + call pl_update (pl, v, Mems[ll_out]) + } + + # Compress the mask if excessive free space has accumulated. + if (PL_NEEDCOMPRESS(pl)) + call pl_compress (pl) + + call sfree (sp) +end diff --git a/sys/plio/plreq.gx b/sys/plio/plreq.gx new file mode 100644 index 00000000..470b4484 --- /dev/null +++ b/sys/plio/plreq.gx @@ -0,0 +1,27 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> + +# PLR_EQUAL -- Compare two range lists for equality. + +bool procedure plr_equal$t (r1, r2) + +PIXEL r1[3,ARB] #I range list 1 +PIXEL r2[3,ARB] #I range list 2 + +int i +int len1, len2 + +begin + len1 = RL_LEN(r1) + len2 = RL_LEN(r2) + + if (len1 != len2) + return (false) + + do i = RL_FIRST, len1 + if (r1[1,i] != r2[1,i] || r1[2,i] != r2[2,i] || r1[3,i] != r2[3,i]) + return (false) + + return (true) +end diff --git a/sys/plio/plrio.x b/sys/plio/plrio.x new file mode 100644 index 00000000..0cf2b8d9 --- /dev/null +++ b/sys/plio/plrio.x @@ -0,0 +1,350 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <plio.h> + +.help PLRIO +.nf --------------------------------------------------------------------------- +PLRIO -- A small package used to provide a means for efficient random +sampling (at the pixel level) of large PLIO masks. In other words, if we have +a large mask and want to determine the values of successive mask pixels at +random locations in the mask, this package provides a more efficient means +for doing so than calling a routine such as PL_GLPI. The mask must already +exist; means are not provided within this package for creating or editing +masks, only for reading them. + + plr = plr_open (pl, plane, buflimit) + plr_setrect (plr, x1,y1, x2,y2) + mval = plr_getpix (plr, x, y) + plr_getlut (plr, bufp, xsize,ysize, xblock,yblock) + plr_close (plr) + +PLR_OPEN opens the indicated 2 dimensional plane of the N dimensional mask PL. +Buffer space used to provide an efficient means of randomly sampling the mask +will be kept to within approximately BUFLIMIT integer units of storage (the +internal table used to sample the mask is type integer, so BUFLIMIT is the +approximate number of entries in the table). Random sampling of the mask is +provided by the integer function PLR_GETPIX, which returns the mask value at +the point [i,j] within the specified plane. PLR_SETRECT may be called before +calling PLR_GETPIX to set the clipping rectangle, which defaults to the +boundaries of the mask. If a PLR_GETPIX call references outside the clipping +region, ERR will be returned as the mask value (normal mask values are >= 0). +Use of a clipping region other than the boundaries of the full mask can avoid +the need for redundant clipping operations in the client. For cases when +even the function call overhead of PLR_GETPIX is too much, the lookup table +may be directly accessed via a call to PLR_GETLUT. Table references which +resolve to a negative valued table entry should call PLR_GETPIX to get the +mask value, otherwise the table value is the mask value. PLR_CLOSE should +be called to free the PLRIO table space (which can be extensive) when no longer +needed. +.endhelp ---------------------------------------------------------------------- + +define DEF_BUFLIMIT (128*128) # internal buffer size +define LEN_STACK (4*32) # max mask size = 2**LEN_STACK + +# If any of the following are changed check that pmio$pmrio.x is consistent. +define LEN_PLRDES 20 +define PLR_PL Memi[$1] # main PLIO descriptor +define PLR_NCOLS Memi[$1+1] # table width +define PLR_NLINES Memi[$1+2] # table height +define PLR_XBLOCK Memi[$1+3] # table blocking factor, X +define PLR_YBLOCK Memi[$1+4] # table blocking factor, Y +define PLR_BUFP Memi[$1+5] # buffer pointer +define PLR_X1 Memi[$1+6] # clipping rectangle +define PLR_Y1 Memi[$1+7] # clipping rectangle +define PLR_X2 Memi[$1+8] # clipping rectangle +define PLR_Y2 Memi[$1+9] # clipping rectangle +define PLR_PLANE Memi[$1+10+($2)-1] # plane to be accessed + +define COMPLEX -1 # table bin -> compex region +define LEN_REGDES 4 # region descriptor +define V1 Memi[$1+($2)-1] +define V2 Memi[$1+2+($2)-1] + + +# PLR_OPEN -- Open a PLIO mask for random pixel access. Provides efficient +# random pixel level access to any size mask. This is a 2-dimensional +# operator, but can be used to sample any 2-dim plane of an N-dim mask. + +pointer procedure plr_open (pl, plane, buflimit) + +pointer pl #I PLIO descriptor +int plane[ARB] #I 2-dim plane to be accessed +int buflimit #I approximate table size, or 0 if don't care + +int v1[PL_MAXDIM], v2[PL_MAXDIM] +int maxpix, ndim, npix, mval, i, j +int msize[2], tsize[2], block[2], vm[2] +pointer sp, stack, plr, bufp, el, rp +errchk calloc, malloc, plvalid +bool pl_sectnotconst() + +begin + call plvalid (pl) + call smark (sp) + call salloc (stack, LEN_STACK * LEN_REGDES, TY_STRUCT) + + # Allocate the PLRIO descriptor. + call calloc (plr, LEN_PLRDES, TY_STRUCT) + + # Set the plane to be accessed. + ndim = PL_NAXES(pl) + do i = 1, 2 + msize[i] = PL_AXLEN(pl,i) + + do i = 1, PL_MAXDIM + if (i > ndim) { + PLR_PLANE(pl,i) = 1 + v1[i] = 1 + v2[i] = 1 + } else if (i > 2) { + PLR_PLANE(pl,i) = plane[i] + v1[i] = plane[i] + v2[i] = plane[i] + } + + # Get the maximum table size in pixels. + if (buflimit <= 0) + maxpix = DEF_BUFLIMIT + else + maxpix = buflimit + + # Determine the blocking factors required to keep the lookup table + # within the given size limit. + + block[1] = 1; block[2] = 1 + while ((msize[1] / block[1]) * (msize[2] / block[2]) > maxpix) + do i = 1, 2 + block[i] = min (msize[i], block[i]*2) + + # Compute the lookup table size. + do i = 1, 2 + tsize[i] = (msize[i] + block[i]-1) / block[i] + + # Allocate the table space. + call malloc (bufp, tsize[1] * tsize[2], TY_INT) + + # Compute the lookup table. Since the lookup table can be large, + # e.g., a quarter million elements for a 512sq table, we don't want + # to directly compute the value of each bufp[i,j]. Instead, we examine + # a region of the table, starting with the entire table, and if the + # corresponding region of the mask is not filled with the same mask + # value, we divide the region into 4 quadrants and examine each in + # turn, and so on until the nonconstant regions are the size of one + # table bin (pixel), which we conclude maps to a COMPLEX (nonconstant) + # region of the mask. By this technique, only table bins which map + # to complex mask regions need be evaluated, and entire large regions + # of the mask are quickly dealt with. + + # Push the entire mask area on the stack as the first region. + el = stack + do i = 1, 2 { + V1(el,i) = 1 + V2(el,i) = tsize[i] + } + + repeat { + # Get the mask coordinates of the next region on the stack. + do i = 1, 2 { + v1[i] = (V1(el,i) - 1) * block[i] + 1 + v2[i] = min (msize[i], V2(el,i) * block[i]) + } + + # Examine the region to see if the associated region of the mask + # consists entirely of a single mask value. + + if (pl_sectnotconst (pl, v1, v2, ndim, mval)) { + if (V1(el,1) == V2(el,1) && V1(el,2) == V2(el,2)) { + # This single table pixel maps to a complex mask region. + Memi[bufp+(V1(el,2)-1)*tsize[1]+V1(el,1)-1] = COMPLEX + + } else { + # Divide the nonzero mask region into four quadrants + # and recursively examine each in turn. + + # Compute the coordinates of the central pixel in vm. + do i = 1, 2 + vm[i] = (V1(el,i) + V2(el,i) + 1) / 2 + + # Save the currently stacked region in v1/v2. + v1[1] = V1(el,1); v1[2] = V1(el,2) + v2[1] = V2(el,1); v2[2] = V2(el,2) + + if ((el-stack)/LEN_REGDES+4 >= LEN_STACK) + call syserrs (SYS_PLSTKOVFL, "plr_open") + + # Push the four quadrants of this region on the stack. + # If the region we are subdividing is only one pixel + # wide in either axis then only two of the regions will + # be valid. The invalid regions will have zero pixels + # in one axis or the other, i.e. (v2[i] < v1[i]). If + # a region is invalid discard it by not advancing the + # stack pointer. + + V1(el,1) = v1[1]; V1(el,2) = vm[2] + V2(el,1) = vm[1]-1; V2(el,2) = v2[2] + if (V1(el,1) <= V2(el,1) && V1(el,2) <= V2(el,2)) + el = el + LEN_REGDES + + V1(el,1) = vm[1]; V1(el,2) = vm[2] + V2(el,1) = v2[1]; V2(el,2) = v2[2] + if (V1(el,1) <= V2(el,1) && V1(el,2) <= V2(el,2)) + el = el + LEN_REGDES + + V1(el,1) = v1[1]; V1(el,2) = v1[2] + V2(el,1) = vm[1]-1; V2(el,2) = vm[2]-1 + if (V1(el,1) <= V2(el,1) && V1(el,2) <= V2(el,2)) + el = el + LEN_REGDES + + V1(el,1) = vm[1]; V1(el,2) = v1[2] + V2(el,1) = v2[1]; V2(el,2) = vm[2]-1 + if (V1(el,1) <= V2(el,1) && V1(el,2) <= V2(el,2)) + el = el + LEN_REGDES + } + } else { + # Set entire region to a constant mask value. + npix = V2(el,1) - V1(el,1) + 1 + do j = V1(el,2), V2(el,2) { + rp = bufp + (j-1) * tsize[1] + V1(el,1) - 1 + if (npix == 1) { + Memi[rp] = mval + } else if (npix < 8) { + do i = 1, npix + Memi[rp+i-1] = mval + } else { + if (mval == 0) + call aclri (Memi[rp], npix) + else + call amovki (mval, Memi[rp], npix) + } + } + } + + # Pop stack. + el = el - LEN_REGDES + + } until (el < stack) + + # Initialize the PLRIO descriptor. + PLR_PL(plr) = pl + PLR_NCOLS(plr) = tsize[1] + PLR_NLINES(plr) = tsize[2] + PLR_XBLOCK(plr) = block[1] + PLR_YBLOCK(plr) = block[2] + PLR_BUFP(plr) = bufp + PLR_X1(plr) = 1 + PLR_Y1(plr) = 1 + PLR_X2(plr) = msize[1] + PLR_Y2(plr) = msize[2] + + call sfree (sp) + return (plr) +end + + +# PLR_GETPIX -- Return the value of the given mask pixel, identified by the +# 2-dim coordinates of the pixel relative to the plane of the N-dim mask +# specified at open time. + +int procedure plr_getpix (plr, i, j) + +pointer plr #I PLR descriptor +int i, j #I plane-relative coordinates of pixel + +pointer pl, ll_src +int ii, jj, mval, np +pointer pl_access() +int pl_l2pi() +errchk pl_access + +begin + # Clip to the specified region of the mask. + if (i < PLR_X1(plr) || i > PLR_X2(plr)) + return (ERR) + if (j < PLR_Y1(plr) || j > PLR_Y2(plr)) + return (ERR) + + # Map mask pixel coordinates to lookup table bin. + ii = (i - 1) / PLR_XBLOCK(plr) + jj = (j - 1) / PLR_YBLOCK(plr) + + # Get the lookup table value of the given bin. + mval = Memi[PLR_BUFP(plr)+jj*PLR_NCOLS(plr)+ii] + + # Access the original mask to get value if complex region. + if (mval == COMPLEX) { + pl = PLR_PL(plr) + PLR_PLANE(plr,2) = j + ll_src = pl_access (pl, PLR_PLANE(plr,1)) + np = pl_l2pi (Mems[ll_src], i, mval, 1) + } + + return (mval) +end + + +# PLR_GETLUT -- Obtain the buffer pointer and scaling information of the +# internal lookup table, so that direct table references may be made to +# minimize overhead in particularly demanding applications. This is not +# recommended unless absolutely necessary, as PLR_GETPIX is easier and +# safer to use and nearly as efficient. The strategy for using the table +# is to use the blocking factors and XSIZE to map a 2dim mask coordinate +# into a table offset, and access the table to get the table value. +# If this is negative PLR_GETPIX should be called to compute the mask +# value, else the table value is the mask value. + +procedure plr_getlut (plr, bufp, xsize,ysize, xblock,yblock) + +pointer plr #I PLR descriptor +pointer bufp #O lookup table buffer pointer (int *) +int xsize,ysize #O table size +int xblock,yblock #O blocking factors + +begin + bufp = PLR_BUFP(plr) + xsize = PLR_NCOLS(plr) + ysize = PLR_NLINES(plr) + xblock = PLR_XBLOCK(plr) + yblock = PLR_YBLOCK(plr) +end + + +# PLR_SETRECT -- Set the clipping region for PLR_GETPIX. + +procedure plr_setrect (plr, x1,y1, x2,y2) + +pointer plr #I PLR descriptor +int x1,y1 #I lower left corner of region +int x2,y2 #I upper right corner of region + +pointer pl +define oob_ 91 +errchk syserrs + +begin + pl = PLR_PL(plr) + + if (x1 < 1 || x1 > PL_AXLEN(pl,1)) + goto oob_ + if (x2 < 1 || x2 > PL_AXLEN(pl,1)) + goto oob_ + if (y1 < 1 || y1 > PL_AXLEN(pl,2)) + goto oob_ + if (y2 < 1 || y2 > PL_AXLEN(pl,2)) +oob_ call syserrs (SYS_PLREFOOB, "plr_setrect") + + PLR_X1(plr) = x1; PLR_Y1(plr) = y1 + PLR_X2(plr) = x2; PLR_Y2(plr) = y2 +end + + +# PLR_CLOSE -- Free a PLRIO descriptor. + +procedure plr_close (plr) + +pointer plr #I PLR descriptor + +begin + call mfree (PLR_BUFP(plr), TY_INT) + call mfree (plr, TY_STRUCT) +end diff --git a/sys/plio/plrop.x b/sys/plio/plrop.x new file mode 100644 index 00000000..b111a359 --- /dev/null +++ b/sys/plio/plrop.x @@ -0,0 +1,93 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <plset.h> +include <plio.h> + +# PL_ROP -- Perform a rasterop operation from the source mask to the +# destination mask at the given offsets. The source and destination need +# not be the same size or dimensionality, but out of bounds references are +# not permitted. If the source is of lesser dimensionality than the +# indicated section of the destination, then the source will be rewound +# and reread as necessary to operate upon the entire destination subregion, +# e.g., a line source mask may be applied to successive lines of a plane, +# or a plane mask may be applied to successive planes of a 3D mask. +# The source and destination masks may be the same if desired, but if the +# source and destination regions overlap feedback may occur (this could be +# fixed). With some rasterops, e.g, PIX_SET or PIX_CLR, no source mask is +# required, and pl_src=NULL is permitted. + +procedure pl_rop (pl_src, vs_src, pl_dst, vs_dst, vn, rop) + +pointer pl_src #I source mask or NULL +long vs_src[PL_MAXDIM] #I start vector in source mask +pointer pl_dst #I destination mask (required) +long vs_dst[PL_MAXDIM] #I start vector in destination mask +long vn[PL_MAXDIM] #I vector giving subregion size +long rop #I rasterop + +bool need_src +pointer sp, ll_out, ll_src, ll_dst, ol_src, ol_dst +long v_src[PL_MAXDIM], v_dst[PL_MAXDIM] +long ve_src[PL_MAXDIM], ve_dst[PL_MAXDIM] + +int plloop() +pointer pl_access() +errchk syserr, plvalid, plsslv, pl_access + +begin + call plvalid (pl_dst) + need_src = R_NEED_SRC(rop) + if (need_src && pl_src == NULL) + call syserr (SYS_PLNULLSRC) + + call smark (sp) + call salloc (ll_out, LL_MAXLEN(pl_dst), TY_SHORT) + + # Initialize the N-dimensional loop counters. + call plsslv (pl_dst, vs_dst, vn, v_dst, ve_dst) + if (need_src) + call plsslv (pl_src, vs_src, vn, v_src, ve_src) + else + ll_src = ll_out # any valid pointer will do + + # Perform the operation. + ol_dst = -1 + repeat { + # Get a line from each mask. The DST linelist is required, + # even if R_NEED_DST(rop) is false, because the DST size + # parameters determine the size of the output list, and the + # rop may only apply to a portion of the DST list. + + ll_dst = pl_access (pl_dst, v_dst) + if (need_src) + ll_src = pl_access (pl_src, v_src) + + # Perform the rasterop operation upon one line of the mask. + # Note that if successive mask lines point to the same encoded + # line list, we only have to compute the result once. + + if (ll_src != ol_src || ll_dst != ol_dst) { + call pl_linerop (Mems[ll_src], vs_src[1], PL_MAXVAL(pl_src), + Mems[ll_dst], vs_dst[1], PL_MAXVAL(pl_dst), + Mems[ll_out], vn[1], rop) + ol_src = ll_src + ol_dst = ll_dst + } + + # Update the affected line of the destination mask. + call pl_update (pl_dst, v_dst, Mems[ll_out]) + + # If the end of the input mask is reached, rewind it and go again. + if (need_src) + if (plloop (v_src,vs_src,ve_src,PL_NAXES(pl_src)) == LOOP_DONE) + call amovi (vs_src, v_src, PL_NAXES(pl_src)) + + } until (plloop (v_dst, vs_dst, ve_dst, PL_NAXES(pl_dst)) == LOOP_DONE) + + # Compress the mask if excessive free space has accumulated. + if (PL_NEEDCOMPRESS(pl_dst)) + call pl_compress (pl_dst) + + call sfree (sp) +end diff --git a/sys/plio/plrpr.gx b/sys/plio/plrpr.gx new file mode 100644 index 00000000..f0004515 --- /dev/null +++ b/sys/plio/plrpr.gx @@ -0,0 +1,56 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PLR_PRINT -- Print a range list on the given output stream. + +procedure plr_print$t (rl, fd, label, firstcol, maxcol) + +PIXEL rl[3,ARB] #I range list +int fd #I output file +char label[ARB] #I line label +int firstcol #I first column for output +int maxcol #I width of formatted output + +pointer sp, buf +int col, rn, r_len, x, n, pv +int strlen() + +begin + call smark (sp) + call salloc (buf, SZ_LINE, TY_CHAR) + + # Output the line label and advance to the first column. If the label + # extends beyond the first column, start a new line. + + call putline (fd, label) + col = strlen (label) + 1 + if (col > firstcol) + call pl_debugout (fd, "", col, firstcol, maxcol) + + r_len = RL_LEN(rl) + + # Decode the range list proper. + do rn = RL_FIRST, r_len { + x = RL_X(rl,rn) + n = RL_N(rl,rn) + pv = RL_V(rl,rn) + + if (n == 1) { + call sprintf (Memc[buf], SZ_LINE, "%d(%d)") + call pargi (x) + call pargi (pv) + } else { + call sprintf (Memc[buf], SZ_LINE, "%d-%d(%d)") + call pargi (x) + call pargi (x+n-1) + call pargi (pv) + } + + call pl_debugout (fd, Memc[buf], col, firstcol, maxcol) + } + + call pl_debugout (fd, "", col, firstcol, maxcol) + call sfree (sp) +end diff --git a/sys/plio/plrrop.gx b/sys/plio/plrrop.gx new file mode 100644 index 00000000..dcc961b2 --- /dev/null +++ b/sys/plio/plrrop.gx @@ -0,0 +1,195 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> +include "../plrseg.h" + +# PL_RANGEROP -- Rasterop operation between source and destination range lists. +# The indicated rasterop operation is performed upon the source and destination +# range lists, writing the result to RL_OUT, which is a copy of RL_DST except +# for the region affected by the rasterop operation (note that the destination +# range list cannot be edited in place since it may change size). + +procedure pl_rangerop$t (rl_src, xs, src_maxval, + rl_dst, ds, dst_maxval, rl_out, npix, rop) + +PIXEL rl_src[3,ARB] #I source range list +int xs #I starting pixel index in src range list +int src_maxval #I max pixel value in src mask +PIXEL rl_dst[3,ARB] #I destination range list +int ds #I starting pixel index in dst range list +int dst_maxval #I max pixel value in dst mask +PIXEL rl_out[3,ARB] #O output list (edited version of rl_dst) +int npix #I number of pixels to convert +int rop #I rasterop + +bool need_src, need_dst, rop_enable +PIXEL data, src_value, v_src, v_dst, pv +int segsize, opcode, x, i, np, rn_o, p +int d_src[LEN_PLRDES], d_dst[LEN_PLRDES] + +begin + need_src = R_NEED_SRC(rop) + need_dst = R_NEED_DST(rop) + opcode = R_OPCODE(rop) + data = R_DATA(rop) + + # Pixel value to be used if input mask is boolean. + if (src_maxval == 1) { + src_value = data + if (src_value <= 0) + src_value = dst_maxval + } + + # Advance to the desired position in the source list, discarding + # the unused ranges. The point XS may lie within a range or in a + # zero area of the input line. + + if (need_src) { + x = 1 + plr_init (rl_src, d_src) + do i = 1, ARB { + np = min (plr_nleft(d_src), xs - x) + plr_getseg (rl_src, d_src, np, v_src) + x = x + np + if (x >= xs || np == 0) + break + } + } + + # Advance through both the source and destination lists, extracting + # line segments which have a constant value in each input list; the + # values for the two lists may differ. Apply the given rasterop to + # the source and destination pixel values and write each line segment + # as a range to the output list. If the ranges in the two input lists + # differ (randomly overlap) then the output list will generally be + # more fragmented, i.e., have more ranges of constant value. As each + # output range is generated compare it with the previous range to see + # if they can be joined, as applying a rasterop may cause two different + # ranges to have the same value. + + x = 1 + rn_o = RL_FIRST + segsize = ds - 1 + rop_enable = false + plr_init (rl_dst, d_dst) + + do i = 1, ARB { + # Set up for the next segment (before, in, and after the region to + # which the ROP applies), when the current segment is exhausted. + + if (segsize <= 0) + if (!rop_enable) { + # Begin processing central region. + segsize = npix + rop_enable = true + if (segsize <= 0) + next + } else { + # Begin processing final region. + segsize = ARB + rop_enable = false + } + + # Determine the length of the next output segment. This is the + # largest segment of constant value formed by the intersection of + # the two lists. If bounds checking has been properly performed + # then it should not be possible to see nleft=zero on either input + # list. Note that zeroed regions are valid data here. + + np = min (segsize, plr_nleft(d_dst)) + if (need_src && rop_enable && plr_nleft(d_src) > 0) + np = min (np, plr_nleft(d_src)) + if (np <= 0) + break + + # Get the segment value and advance the line pointers. We must + # read the DST list whether or not we will use the data, since + # the list pointer must be advanced NPIX pixels so that we may + # copy the remainder of the list after the loop. + + plr_getseg (rl_dst, d_dst, np, v_dst) + if (rop_enable) { + # Get v_src. + if (need_src) { + v_src = 0 + if (plr_nleft (d_src) > 0) + plr_getseg (rl_src, d_src, np, v_src) + + if (R_NOTSRC(rop)) { + v_src = not (v_src) + if (src_maxval != 0) + v_src = and (int(v_src), src_maxval) + } + + if (v_src != 0 && src_maxval == 1) + v_src = src_value + } + + # Get v_dst. + if (need_dst) { + if (R_NOTDST(rop)) { + v_dst = not (v_dst) + if (dst_maxval != 0) + v_dst = and (int(v_dst), dst_maxval) + } + } + + # Apply the rasterop. + switch (opcode) { + case PIX_CLR: + pv = 0 + case PIX_SET: + pv = data + case PIX_SRC, PIX_NOTSRC: + pv = v_src + case PIX_DST, PIX_NOTDST: + pv = v_dst + case PIX_SRC_AND_DST, PIX_SRC_AND_NOTDST, PIX_NOTSRC_AND_DST: + pv = and (v_src, v_dst) + case PIX_SRC_OR_DST, PIX_SRC_OR_NOTDST, PIX_NOTSRC_OR_DST: + pv = or (v_src, v_dst) + case PIX_SRC_XOR_DST: + pv = xor (v_src, v_dst) + case PIX_NOT_SRC_AND_DST: + pv = not (and (v_src, v_dst)) + case PIX_NOT_SRC_OR_DST: + pv = not (or (v_src, v_dst)) + case PIX_NOT_SRC_XOR_DST: + pv = not (xor (v_src, v_dst)) + } + + # Mask the high bits to prevent negative values, or map int + # to bool for the case of a boolean output mask. + + if (dst_maxval == 1 && pv != 0) + pv = 1 + else if (dst_maxval > 1) + pv = and (int(pv), dst_maxval) + + } else + pv = v_dst + + # Output a nonzero range. + if (pv > 0) { + p = rn_o - 1 + if (p >= RL_FIRST && + pv == rl_out[3,p] && x == rl_out[1,p] + rl_out[2,p]) { + # Merge new range with previous one. + rl_out[2,p] = rl_out[2,p] + np + } else { + rl_out[1,rn_o] = x + rl_out[2,rn_o] = np + rl_out[3,rn_o] = pv + rn_o = rn_o + 1 + } + } + + x = x + np + segsize = segsize - np + } + + # Update the range list header. + call amov$t (rl_dst, rl_out, (RL_FIRST - 1) * 3) + RL_LEN(rl_out) = rn_o - 1 +end diff --git a/sys/plio/plrseg.h b/sys/plio/plrseg.h new file mode 100644 index 00000000..f37372c3 --- /dev/null +++ b/sys/plio/plrseg.h @@ -0,0 +1,58 @@ +# PLRSEG.H -- Macros for sequentially reading segments of a range list. +# +# plr_init (rl, descriptor) +# npix = plr_nleft (descriptor) +# val = plr_getseg (rl, descriptor, npix, value) +# +# plr_init Initialize descriptor for sequential i/o from the rangelist RL. +# plr_nleft Number of pixels left in the current line segment of constant +# value. Zero is returned at the EOL. +# plr_getseg Read NPIX pixels from the current segment, advancing to the +# next segment automatically when the the current segment is +# exhausted. +# +# The descriptor is an integer array, the contents of which are hidden from +# the application using these macros. + +# Range list i/o descriptor. +define LEN_PLRDES 4 +define rd_nleft $1[1] +define rd_value $1[2] +define rd_x $1[3] +define rd_rn $1[4] + +# PLR_INIT -- Initialize the rangelist descriptor. +define (plr_init, { # $1=rl $2=des + rd_x($2) = 1 + rd_rn($2) = RL_FIRST + plr_nextseg ($1, $2) +}) + +# PLR_NLEFT -- Number of pixels left in the current segment. +define plr_nleft rd_nleft($1) + +# PLR_GETSEG -- Read pixels from the current segment. +define (plr_getseg, { # $1=rl $2=des $3=npix $4=value + $4 = rd_value($2) + rd_x($2) = rd_x($2) + $3 + rd_nleft($2) = rd_nleft($2) - $3 + if (rd_nleft($2) <= 0) + plr_nextseg ($1, $2) +}) + +# PLR_NEXTSEG -- Set up the next segment (internal routine). +define (plr_nextseg, { # $1=rl $2=des + if (rd_rn($2) <= RL_LEN($1)) { + if ($1[1,rd_rn($2)] > rd_x($2)) { + rd_value($2) = 0 + rd_nleft($2) = $1[1,rd_x($2)] - rd_x($2) + } else { + rd_value($2) = $1[3,rd_rn($2)] + rd_nleft($2) = $1[2,rd_rn($2)] + rd_rn($2) = rd_rn($2) + 1 + } + } else if (rd_x($2) <= RL_AXLEN($1)) { + rd_value($2) = 0 + rd_nleft($2) = RL_AXLEN($1) - rd_x($2) + 1 + } +}) diff --git a/sys/plio/plsave.x b/sys/plio/plsave.x new file mode 100644 index 00000000..1b0101d3 --- /dev/null +++ b/sys/plio/plsave.x @@ -0,0 +1,86 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_SAVE -- Save a mask in a buffer in a machine independent format. The user +# supplied buffer will be resized if necessary to hold the full encoded mask. +# If a NULL buffer pointer is given, a new buffer will be allocated with the +# pointer value overwriting the NULL (hence NULL must not be passed as a +# constant in the argument list). The length of the encoded mask in words is +# returned as the function value; this value will be less than BUFLEN is the +# user supplied buffer is larger than it needs to be to store the mask, i.e., +# the user buffer is not resized or reallocated if it is large enough to store +# the mask. The existing contents of the buffer will be overwritten. Multiple +# calls may be made to checkpoint the mask, allowing rollback to an earlier +# state. + +int procedure pl_save (pl, bp, buflen, flags) + +pointer pl #I mask descriptor +pointer bp #U buffer pointer (to short), or NULL +int buflen #U buffer length, shorts +int flags #I not used at present + +pointer sp, index, ex, op +int sz_index, n_buflen +int pl_p2li() +pointer coerce() +errchk malloc, realloc, pl_compress + +begin + call smark (sp) + call salloc (ex, LEN_PLEXTERN, TY_STRUCT) + call salloc (index, PL_NLP(pl) * 3 + LL_CURHDRLEN, TY_SHORT) + + # Eliminate any wasted space in the mask, and compute the amount + # of space needed to store the compressed mask. Compress the index + # first to eliminate wasted space; this can make a big difference + # for a sparse or empty mask. + + call pl_compress (pl) + sz_index = pl_p2li (PL_LP(pl,1), 1, Mems[index], PL_NLP(pl)) + #n_buflen = (LEN_PLEXTERN * SZ_STRUCT + PL_LLLEN(pl) * SZ_SHORT + + n_buflen = (LEN_PLEXTERN * SZ_MII_INT + PL_LLLEN(pl) * SZ_SHORT + + sz_index * SZ_SHORT) / SZ_SHORT + + # Allocate or resize the output buffer. + if (bp == NULL) { + call malloc (bp, n_buflen, TY_SHORT) + buflen = n_buflen + } else if (n_buflen > buflen) { + call realloc (bp, n_buflen, TY_SHORT) + buflen = n_buflen + } + + # Encode and output the external format header structure. + call aclri (Memi[ex], LEN_PLEXTERN) + + PLE_MAGIC(ex) = PL_MAGIC(pl) + PLE_NAXES(ex) = PL_NAXES(pl) + PLE_LLOP(ex) = PL_LLOP(pl) + PLE_LLLEN(ex) = PL_LLLEN(pl) + PLE_MAXLINE(ex) = PL_MAXLINE(pl) + PLE_MAXVAL(ex) = PL_MAXVAL(pl) + PLE_NLP(ex) = PL_NLP(pl) + PLE_NLPX(ex) = sz_index + PLE_EXLEN(ex) = n_buflen + + op = bp + call amovl (PL_AXLEN(pl,1), PLE_AXLEN(ex,1), PL_MAXDIM) + call miipak32 (Memi[ex], Memi[coerce(op,TY_SHORT,TY_INT)], + LEN_PLEXTERN, TY_STRUCT) + #op = op + (LEN_PLEXTERN * SZ_STRUCT) / SZ_SHORT + op = op + (LEN_PLEXTERN * SZ_MII_INT) / SZ_SHORT + + # Append the compressed index... + call miipak16 (Mems[index], Mems[op], sz_index, TY_SHORT) + op = op + sz_index + + # and the line list buffer. + call miipak16 (LL(pl,0), Mems[op], PL_LLLEN(pl), TY_SHORT) + op = op + PL_LLLEN(pl) + + call sfree (sp) + return (op - bp) +end diff --git a/sys/plio/plsavef.x b/sys/plio/plsavef.x new file mode 100644 index 00000000..25575e5f --- /dev/null +++ b/sys/plio/plsavef.x @@ -0,0 +1,59 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_SAVEF -- Store a mask in external format in a binary file. This simple +# code permits only one mask per file; more sophisticated mask storage +# facilities are planned. These will likely obsolete this routine. + +procedure pl_savef (pl, fname, title, flags) + +pointer pl #I mask descriptor +char fname[ARB] #I file name +char title[ARB] #I mask title +int flags #I save flags + +int fd, masklen, buflen, junk +pointer sp, fullname, extn, bp, sv +errchk open, pl_save, write, mfree +int open(), fnextn(), strlen(), pl_save() +bool strne() + +begin + call smark (sp) + call salloc (sv, LEN_SVDES, TY_STRUCT) + call salloc (extn, SZ_FNAME, TY_CHAR) + call salloc (fullname, SZ_PATHNAME, TY_CHAR) + + # Add the ".pl" filename extension if not already present. + call strcpy (fname, Memc[fullname], SZ_PATHNAME) + junk = fnextn (fname, Memc[extn], SZ_FNAME) + if (strne (Memc[extn], "pl")) + call strcat (".pl", Memc[fullname], SZ_PATHNAME) + + # The update flag is required to allow overwriting an existing mask. + if (and (flags, PL_UPDATE) != 0) + iferr (call delete (Memc[fullname])) + ; + + # Encode the mask. + bp = NULL + masklen = pl_save (pl, bp, buflen, flags) + + # Set up the savefile descriptor. + SV_MAGIC(sv) = PLIO_SVMAGIC + SV_TITLELEN(sv) = strlen (title) + 1 + SV_MASKLEN(sv) = masklen + + # Write the savefile. + fd = open (Memc[fullname], NEW_FILE, BINARY_FILE) + + call miiwritei (fd, Memi[sv], LEN_SVDES) + call miiwritec (fd, title, SV_TITLELEN(sv)) + call write (fd, Mems[bp], masklen * SZ_SHORT) + call mfree (bp, TY_SHORT) + + call close (fd) + call sfree (sp) +end diff --git a/sys/plio/plsaveim.x b/sys/plio/plsaveim.x new file mode 100644 index 00000000..8e1b4b54 --- /dev/null +++ b/sys/plio/plsaveim.x @@ -0,0 +1,122 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <imhdr.h> +include <imset.h> +include <mach.h> +include <plset.h> +include <plio.h> + +# PL_SAVEIM -- Save a mask in a conventional image, i.e., convert a mask to +# an image. + +procedure pl_saveim (pl, imname, title, flags) + +pointer pl #I mask descriptor +char imname[ARB] #I image name or section +char title[ARB] #I mask "title" string +int flags #I bitflags + +bool sampling +pointer im, px, im_pl, bp +int npix, naxes, depth, maxdim, mode, i, locstr, locmem +long v_in[PL_MAXDIM], v_out[PL_MAXDIM], vn[PL_MAXDIM] +long vs_l[PL_MAXDIM], vs_p[PL_MAXDIM] +long ve_l[PL_MAXDIM], ve_p[PL_MAXDIM] + +pointer immap() +long clktime() +int impnli(), imaccess(), imstati(), strlen() +errchk immap, syserrs, impnli + +begin + # Open the new output image. + mode = NEW_IMAGE + if (and (flags, PL_UPDATE) != 0) + if (imaccess (imname, 0) == YES) + mode = READ_WRITE + + im = immap (imname, mode, 0) + + # Reload the image header from the "title" string, if any. + if (strlen(title) > 0) { + call zlocva (title, locstr) + call zlocva (Memc, locmem) + bp = locstr - locmem + 1 + call im_pmldhdr (im, bp) + } + + # Initialize a new image to the size of the mask. If updating an + # existing image the sizes must match. + + call pl_gsize (pl, naxes, vn, depth) + maxdim = min (IM_MAXDIM, PL_MAXDIM) + npix = vn[1] + + if (mode == NEW_IMAGE) { + IM_NDIM(im) = naxes + IM_PIXTYPE(im) = TY_SHORT + if (PL_MAXVAL(pl) > MAX_SHORT) + IM_PIXTYPE(im) = TY_INT + call amovl (vn, IM_LEN(im,1), maxdim) + } else { + if (naxes != IM_NDIM(im)) { + call imunmap (im) + call syserrs (SYS_IMPLSIZE, imname) + } + do i = 1, naxes + if (vn[i] != IM_LEN(im,i)) { + call imunmap (im) + call syserrs (SYS_IMPLSIZE, imname) + } + } + + # If the image is already a mask internally, check whether any + # subsampling, axis flipping, or axis mapping is in effect. + # If so we can't use PLIO to copy the mask section. + + im_pl = imstati (im, IM_PLDES) + sampling = false + + if (im_pl != NULL) { + call amovkl (long(1), vs_l, maxdim) + call amovl (IM_LEN(im,1), ve_l, maxdim) + call imaplv (im, vs_l, vs_p, maxdim) + call imaplv (im, ve_l, ve_p, maxdim) + + do i = 1, maxdim { + vn[i] = ve_l[i] - vs_l[i] + 1 + if (vn[i] != ve_p[i] - vs_p[i] + 1) { + sampling = true + break + } + } + } + + # If the source image is already a mask internally and no axis + # geometry is in effect in the image section (if any), then we can + # use a PLIO rasterop to efficiently copy the mask subsection. + + if (im_pl != NULL && !sampling) { + # Copy a mask subsection (or entire image if no section). + call pl_rop (pl, vs_l, im_pl, vs_p, vn, PIX_SRC) + call pl_compress (im_pl) + + } else { + # Copy image pixels. Initialize the vector loop indices. + call amovkl (long(1), v_in, maxdim) + call amovkl (long(1), v_out, maxdim) + + # Copy the image. + while (impnli (im, px, v_out) != EOF) { + call pl_glpi (pl, v_in, Memi[px], 0, npix, PIX_SRC) + call amovl (v_out, v_in, maxdim) + } + } + + IM_MIN(im) = 0 + IM_MAX(im) = PL_MAXVAL(pl) + IM_LIMTIME(im) = clktime(0) + + call imunmap (im) +end diff --git a/sys/plio/plsectnc.x b/sys/plio/plsectnc.x new file mode 100644 index 00000000..7aba7fe6 --- /dev/null +++ b/sys/plio/plsectnc.x @@ -0,0 +1,113 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include "pllseg.h" +include <plio.h> + +# PL_SECTNOTCONST -- Test whether the indicated mask image section is constant, +# i.e., all the pixels in the section have the same value. Return this value +# if the region is constant. + +bool procedure pl_sectnotconst (pl_src, v1, v2, ndim, mval) + +pointer pl_src #I mask descriptor +long v1[PL_MAXDIM] #I starting coordinates of section +long v2[PL_MAXDIM] #I ending coordinates of section +int ndim #I section dimension +int mval #O mask value, if constant region + +pointer lp +int ll_src, lval, i +long v[PL_MAXDIM], vs[PL_MAXDIM], ve[PL_MAXDIM], vn[PL_MAXDIM] + +bool pll_const() +int pl_reference(), plloop() +errchk plvalid, plsslv, pl_reference + +begin + call plvalid (pl_src) + + # Initialize the N-dimensional loop counters. + do i = 1, PL_MAXDIM + if (i <= ndim) { + if (v1[i] <= v2[i]) { + vs[i] = v1[i] + vn[i] = v2[i] - v1[i] + 1 + } else { + vs[i] = v2[i] + vn[i] = v1[i] - v2[i] + 1 + } + } else { + vs[i] = 1 + vn[i] = 1 + } + + call plsslv (pl_src, vs, vn, v, ve) + mval = ERR + + # Test each line segment in the section. + repeat { + # Determine if line segment is complex, or is all set to lval. + ll_src = pl_reference (pl_src, v) + if (ll_src == PL_EMPTYLINE) + lval = 0 + else { + lp = Ref (pl_src, ll_src) + if (!pll_const (Mems[lp], vs[1], vn[1], lval)) + return (true) + } + + # Exit if the mask value changes, indicating a complex region. + if (mval == ERR) + mval = lval + else if (mval != lval) + return (true) + + } until (plloop (v, vs, ve, PL_NAXES(pl_src)) == LOOP_DONE) + + return (false) +end + + +# PLL_CONST -- Test whether a section of a line list is set to a constant +# value. If yes, return the value in mval. + +bool procedure pll_const (ll_src, xs, npix, mval) + +short ll_src[ARB] #I input line list +int xs #I first pixel to test +int npix #I length of region to be tested +int mval #O mask value, if constant valued segment + +int nleft, x1, np, v_src, i +int d_src[LEN_PLLDES] + +begin + # Advance to the indicated position in the source list. + x1 = 1 + pll_init (ll_src, d_src) + do i = 1, ARB { + np = min (pll_nleft(d_src), xs - x1) + pll_getseg (ll_src, d_src, np, v_src) + x1 = x1 + np + if (x1 >= xs || np == 0) + break + } + + # Test if the next npix pixels are all set to the same value. + # Note the line list is segmented and we have to read segments until + # we have examined NPIX pixels, or until the mask value changes. + + mval = -1 + for (nleft=npix; nleft > 0; nleft = nleft - np) { + np = min (pll_nleft(d_src), nleft) + pll_getseg (ll_src, d_src, np, v_src) + if (v_src != mval) + if (mval < 0) + mval = v_src + else + return (false) + } + + return (true) +end diff --git a/sys/plio/plsectne.x b/sys/plio/plsectne.x new file mode 100644 index 00000000..c8ca8f6d --- /dev/null +++ b/sys/plio/plsectne.x @@ -0,0 +1,101 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include "pllseg.h" +include <plio.h> + +# PL_SECTNOTEMPTY -- Test whether the indicated mask image section is empty. + +bool procedure pl_sectnotempty (pl_src, v1, v2, ndim) + +pointer pl_src #I mask descriptor +long v1[PL_MAXDIM] #I starting coordinates of section +long v2[PL_MAXDIM] #I ending coordinates of section +int ndim + +pointer lp +int ll_src, i +long v[PL_MAXDIM], vs[PL_MAXDIM], ve[PL_MAXDIM], vn[PL_MAXDIM] + +bool pll_empty() +int pl_reference(), plloop() +errchk plvalid, plsslv, pl_reference + +begin + call plvalid (pl_src) + + # Initialize the N-dimensional loop counters. + do i = 1, PL_MAXDIM + if (i <= ndim) { + if (v1[i] <= v2[i]) { + vs[i] = v1[i] + vn[i] = v2[i] - v1[i] + 1 + } else { + vs[i] = v2[i] + vn[i] = v1[i] - v2[i] + 1 + } + } else { + vs[i] = 1 + vn[i] = 1 + } + + call plsslv (pl_src, vs, vn, v, ve) + + # Test each line segment in the section. + repeat { + ll_src = pl_reference (pl_src, v) + if (ll_src != PL_EMPTYLINE) { + lp = Ref (pl_src, ll_src) + if (!pll_empty (Mems[lp], vs[1], vn[1])) + return (true) + } + } until (plloop (v, vs, ve, PL_NAXES(pl_src)) == LOOP_DONE) + + return (false) +end + + +# PLL_EMPTY -- Test whether a section of a line list is empty. + +bool procedure pll_empty (ll_src, xs, npix) + +short ll_src[ARB] #I input line list +int xs #I first pixel to test +int npix #I length of region to be tested + +int nleft, x1, np, v_src, i +int d_src[LEN_PLLDES] + +begin + # Advance to the indicated position in the source list. + x1 = 1 + pll_init (ll_src, d_src) + do i = 1, ARB { + np = min (pll_nleft(d_src), xs - x1) + pll_getseg (ll_src, d_src, np, v_src) + x1 = x1 + np + if (x1 >= xs || np == 0) + break + } + + # Test if the next npix pixels are zero. + if (pll_nleft(d_src) < npix) + return (false) + else { + pll_getseg (ll_src, d_src, npix, v_src) + return (v_src == 0) + } + + # Test if the next npix pixels are zero. Note the line list is + # segmented and we have to read segments until we have examined NPIX + # pixels, or until a nonzero mask pixel is encountered. + + for (nleft=npix; nleft > 0; nleft = nleft - np) { + np = min (pll_nleft(d_src), nleft) + pll_getseg (ll_src, d_src, np, v_src) + if (v_src != 0) + return (false) + } + + return (true) +end diff --git a/sys/plio/plseti.x b/sys/plio/plseti.x new file mode 100644 index 00000000..c6e9d2b4 --- /dev/null +++ b/sys/plio/plseti.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <plset.h> +include <plio.h> + +# PL_SETI -- Set a PLIO parameter. + +procedure pl_seti (pl, param, value) + +pointer pl #I mask descriptor +int param #I parameter code +int value #I parameter value + +begin + switch (param) { + case P_PRIVATE1: + PL_PRIVATE1(pl) = value + case P_PRIVATE2: + PL_PRIVATE2(pl) = value + case P_MAXLINE: + PL_MAXLINE(pl) = value + case P_DEPTH: + PL_MAXVAL(pl) = MV(value) + default: + call syserr (SYS_PLINVPAR) + } +end diff --git a/sys/plio/plsplane.x b/sys/plio/plsplane.x new file mode 100644 index 00000000..e4a1f3c1 --- /dev/null +++ b/sys/plio/plsplane.x @@ -0,0 +1,15 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_SETPLANE -- Set the 2-Dim plane to be referenced in calls to the pl_box, +# pl_circle, etc. geometric region masking operators. + +procedure pl_setplane (pl, v) + +pointer pl #I mask descriptor +long v[ARB] #I vector defining plane + +begin + call amovl (v, PL_PLANE(pl,1), PL_MAXDIM) +end diff --git a/sys/plio/plssize.x b/sys/plio/plssize.x new file mode 100644 index 00000000..c14e893d --- /dev/null +++ b/sys/plio/plssize.x @@ -0,0 +1,64 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_SSIZE -- Set the size of a mask, i.e., given an existing open mask +# descriptor, create an empty mask with the given dimensionality and size. + +procedure pl_ssize (pl, naxes, axlen, depth) + +pointer pl #I mask descriptor +int naxes #I number of axes (dimensionality of mask) +long axlen[ARB] #I length of each axis +int depth #I mask depth, bits + +int npix, i +pointer sp, px, lp +int pl_p2ls() +errchk malloc, calloc, mfree + +begin + npix = axlen[1] + call smark (sp) + call salloc (px, npix, TY_SHORT) + + # Initialize the old descriptor. + if (PL_LPP(pl) != NULL) + call mfree (PL_LPP(pl), TY_INT) + if (PL_LLBP(pl) != NULL) + call mfree (PL_LLBP(pl), TY_SHORT) + call amovki (1, PL_PLANE(pl,1), PL_MAXDIM) + + # Set up the empty descriptor. + PL_NAXES(pl) = naxes + if (depth > 0) + PL_MAXVAL(pl) = MV(depth) + else + PL_MAXVAL(pl) = MV(PL_MAXDEPTH) + call amovl (axlen, PL_AXLEN(pl,1), naxes) + do i = naxes + 1, PL_MAXDIM + PL_AXLEN(pl,i) = 1 + + # Allocate the line list buffer. + PL_MAXLINE(pl) = (axlen[1] * 3) + LL_CURHDRLEN + PL_LLLEN(pl) = PL_LLBUFLEN + call malloc (PL_LLBP(pl), PL_LLBUFLEN, TY_SHORT) + lp = PL_LLBP(pl) + + # Encode the empty line line-list. + call aclrs (Mems[px], npix) + PL_LLOP(pl) = pl_p2ls (Mems[px], 1, Mems[lp], npix) + + # Set up the initial line list index (all lines empty). + PL_NLP(pl) = 1 + do i = 2, naxes + PL_NLP(pl) = PL_NLP(pl) * axlen[i] + call calloc (PL_LPP(pl), PL_NLP(pl), TY_INT) + + # Set up the LL header for the empty line. + LP_NREFS(lp) = PL_NLP(pl) + LP_SETBLEN(lp, PL_LLOP(pl)) + + call sfree (sp) +end diff --git a/sys/plio/plsslv.x b/sys/plio/plsslv.x new file mode 100644 index 00000000..bb7b21cb --- /dev/null +++ b/sys/plio/plsslv.x @@ -0,0 +1,25 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PLSSLV -- Given two vectors (VS, VN) defining the starting coordinates and +# size of an image section, initialize the "loop index" vector V, and the +# loop-end vector VE. + +procedure plsslv (pl, vs, vn, v, ve) + +pointer pl #I mask descriptor +long vs[PL_MAXDIM] #I vector coordinates of start of section +long vn[PL_MAXDIM] #I vector size of section +long v[PL_MAXDIM] #O vector for i/o (vector loop index) +long ve[PL_MAXDIM] #O vector coordinates of end of section + +int i + +begin + do i = 1, PL_NAXES(pl) { + v[i] = vs[i] + ve[i] = vs[i] + vn[i] - 1 + } +end diff --git a/sys/plio/plstati.x b/sys/plio/plstati.x new file mode 100644 index 00000000..c6659afa --- /dev/null +++ b/sys/plio/plstati.x @@ -0,0 +1,31 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <plset.h> +include <plio.h> + +# PL_STATI -- Stat a PLIO parameter. + +int procedure pl_stati (pl, param) + +pointer pl #I mask descriptor +int param #I parameter code + +int i + +begin + switch (param) { + case P_PRIVATE1: + return (PL_PRIVATE1(pl)) + case P_PRIVATE2: + return (PL_PRIVATE2(pl)) + case P_MAXLINE: + return (PL_MAXLINE(pl)) + case P_DEPTH: + do i = 0, ARB + if (2**i > min (I_PVMAX, PL_MAXVAL(pl))) + return (i) + default: + call syserr (SYS_PLINVPAR) + } +end diff --git a/sys/plio/plsten.x b/sys/plio/plsten.x new file mode 100644 index 00000000..6397af3d --- /dev/null +++ b/sys/plio/plsten.x @@ -0,0 +1,92 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <plset.h> +include <plio.h> + +# PL_STENCIL -- Perform a rasterop operation from the source mask to the +# destination mask at the given offsets, but only within the regions set to +# one in the stencil mask. + +procedure pl_stencil (pl_src, vs_src, pl_dst, vs_dst, pl_stn, vs_stn, vn, rop) + +pointer pl_src #I source mask or NULL +long vs_src[PL_MAXDIM] #I start vector in source mask +pointer pl_dst #I destination mask (required) +long vs_dst[PL_MAXDIM] #I start vector in destination mask +pointer pl_stn #I stencil mask (required) +long vs_stn[PL_MAXDIM] #I start vector in stencil mask +long vn[PL_MAXDIM] #I vector giving subregion size +long rop #I rasterop + +bool need_src +pointer sp, ll_out, ll_src, ll_dst, ll_stn, ol_src, ol_dst, ol_stn +long v_src[PL_MAXDIM], v_dst[PL_MAXDIM], v_stn[PL_MAXDIM] +long ve_src[PL_MAXDIM], ve_dst[PL_MAXDIM], ve_stn[PL_MAXDIM] + +int plloop() +pointer pl_access() +errchk syserr, plvalid, plsslv, pl_access + +begin + call plvalid (pl_dst) + call plvalid (pl_stn) + need_src = R_NEED_SRC(rop) + if (need_src && pl_src == NULL) + call syserr (SYS_PLNULLSRC) + + call smark (sp) + call salloc (ll_out, LL_MAXLEN(pl_dst), TY_SHORT) + + # Initialize the N-dimensional loop counters. + call plsslv (pl_dst, vs_dst, vn, v_dst, ve_dst) + call plsslv (pl_stn, vs_stn, vn, v_stn, ve_stn) + if (need_src) + call plsslv (pl_src, vs_src, vn, v_src, ve_src) + else + ll_src = ll_out # any valid pointer will do + + # Perform the operation. + ol_dst = -1 + repeat { + # Get a line from each mask. + ll_dst = pl_access (pl_dst, v_dst) + ll_stn = pl_access (pl_stn, v_stn) + if (need_src) + ll_src = pl_access (pl_src, v_src) + + # Perform the rasterop operation upon one line of the mask. + # Note that if successive mask lines point to the same encoded + # line list, we only have to compute the result once. + + if (ll_src != ol_src || ll_dst != ol_dst || ll_stn != ol_stn) { + call pl_linestencil (Mems[ll_src], vs_src[1], PL_MAXVAL(pl_src), + Mems[ll_dst], vs_dst[1], PL_MAXVAL(pl_dst), + Mems[ll_stn], vs_stn[1], + Mems[ll_out], vn[1], rop) + + ol_src = ll_src + ol_dst = ll_dst + ol_stn = ll_stn + } + + # Update the affected line of the destination mask. + call pl_update (pl_dst, v_dst, Mems[ll_out]) + + # If the end of the input mask or stencil is reached, + # rewind it and go again. + + if (plloop (v_stn,vs_stn,ve_stn,PL_NAXES(pl_stn)) == LOOP_DONE) + call amovi (vs_stn, v_stn, PL_NAXES(pl_stn)) + if (need_src) + if (plloop (v_src,vs_src,ve_src,PL_NAXES(pl_src)) == LOOP_DONE) + call amovi (vs_src, v_src, PL_NAXES(pl_src)) + + } until (plloop (v_dst, vs_dst, ve_dst, PL_NAXES(pl_dst)) == LOOP_DONE) + + # Compress the mask if excessive free space has accumulated. + if (PL_NEEDCOMPRESS(pl_dst)) + call pl_compress (pl_dst) + + call sfree (sp) +end diff --git a/sys/plio/plubox.x b/sys/plio/plubox.x new file mode 100644 index 00000000..ec3e1f47 --- /dev/null +++ b/sys/plio/plubox.x @@ -0,0 +1,45 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> +include "plbox.h" + + +# PL_UBOX -- Regionrop ufcn for a box (rectangular) region. + +bool procedure pl_ubox (ufd, y, rl_reg, xs, npix) + +pointer ufd #I user function descriptor +int y #I mask line number +int rl_reg[3,ARB] #O output range list for line Y +int xs #O start of edit region in dst mask +int npix #O number of pixels affected + +int rn +bool rl_new + +begin + rl_new = true + rn = RL_FIRST + + if (y >= B_Y1(ufd) && y <= B_Y2(ufd)) { + xs = B_X1(ufd) + npix = B_X2(ufd) - B_X1(ufd) + 1 + + RL_X(rl_reg,rn) = 1 + RL_N(rl_reg,rn) = npix + RL_V(rl_reg,rn) = B_PV(ufd) + + rl_new = (y == B_Y1(ufd)) + rn = rn + 1 + + } else { + npix = 0 + xs = 1 + } + + RL_LEN(rl_reg) = rn - 1 + RL_AXLEN(rl_reg) = npix + + return (rl_new) +end diff --git a/sys/plio/plucircle.x b/sys/plio/plucircle.x new file mode 100644 index 00000000..5a23d20a --- /dev/null +++ b/sys/plio/plucircle.x @@ -0,0 +1,54 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> +include "plcircle.h" + + +# PL_UCIRCLE -- Regionrop ufcn for a circle (circular region), clipped at +# the borders of the mask. + +bool procedure pl_ucircle (ufd, y, rl_reg, xs, npix) + +pointer ufd #I user function descriptor +int y #I mask line number +int rl_reg[3,ARB] #O output range list for line Y +int xs #O first pixel to be edited +int npix #O number of pixels affected + +pointer pl +real radius, dx, dy +int rn, axlen, x1, x1_clipped, x2, x2_clipped + +begin + pl = C_PL(ufd) + rn = RL_FIRST + axlen = PL_AXLEN(pl,1) + radius = C_RADIUS(ufd) + + dy = abs (C_YCEN(ufd) - y) + if (dy <= radius) { + dx = sqrt (radius**2 - dy**2) + x1 = C_XCEN(ufd) - int(dx) + x2 = C_XCEN(ufd) + int(dx) + x1_clipped = max(1, min(axlen, x1)) + x2_clipped = max(1, min(axlen, x2)) + + xs = x1_clipped + npix = x2_clipped - x1_clipped + 1 + + RL_X(rl_reg,rn) = 1 + RL_N(rl_reg,rn) = npix + RL_V(rl_reg,rn) = C_PV(ufd) + rn = rn + 1 + + } else { + npix = 0 + xs = 1 + } + + RL_LEN(rl_reg) = rn - 1 + RL_AXLEN(rl_reg) = npix + + return (true) +end diff --git a/sys/plio/plupdate.x b/sys/plio/plupdate.x new file mode 100644 index 00000000..bb90cc34 --- /dev/null +++ b/sys/plio/plupdate.x @@ -0,0 +1,158 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <mach.h> +include <plset.h> +include <plio.h> + +# PL_UPDATE -- Update the indicated line of a mask, i.e., insert a possibly +# modified line (encoded line list) into an image mask. This is where image +# compression in the Y direction occurs: if the line to be inserted is the +# "empty line", or a copy of the adjacent line earlier in the image, then we +# merely set the new line pointer to point to the line already stored, and +# increment the reference count for that line. When a new mask is created, +# all lines point to the "empty line" line list (PL_EMPTYLINE), which has a +# reference count equal to the number of lines in the mask. +# +# A new line may replace an existing line in storage if space permits and the +# reference count of the existing line is one or less, i.e., the stored line +# list is used only by the image line being updated. Otherwise the new line +# list will be appended to the line list buffer, which is resized to a larger +# size if it overflows. Note that the resize may move the buffer, which is +# why all line "pointers" are actually offsets into the line list buffer. +# +# We do not perform garbage collection on freed lines, rather we keep a count +# of the total amount of freed space (which cannot be reused), allowing the +# entire line list to be rebuilt periodically to reclaim the space, when the +# percentage of wasted space rises to a certain level. Since this can be a +# relatively expensive operation it is only performed by high level, more +# macroscopic operators, e.g., following a full mask rasterop, or before +# writing the mask to external storage. Note also that rebulding the mask +# may shift the stored line lists about, invalidating any line list pointers +# that may be cached in the calling procedure. This is another reason why +# we do not perform mask compression automatically if buffer overflow occurs +# during a line update. + +procedure pl_update (pl, v, ll) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I coordinates of line in the mask +short ll[ARB] #I encoded line list + +pointer o_pp, n_pp +int totlen, axlen, index, i +int o_lp, n_lp, o_len, n_len, b_len + +bool pll_equal() +int pl_alloc() +errchk pl_alloc +define update_ 91 +define oob_ 92 + +begin + # Compute the index of the line in the line pointer array. + if (PL_NAXES(pl) == 2) { + # Optimized for case naxes=2. + index = v[2] + if (index < 1 || index > PL_AXLEN(pl,2)) + goto oob_ + } else { + # Generalized code. + index = 1 + totlen = 1 + do i = 2, PL_NAXES(pl) { + axlen = PL_AXLEN(pl,i) + if (v[i] < 1 || v[i] > axlen) + goto oob_ + index = index + totlen * (v[i] - 1) + totlen = totlen * axlen + } + } + + # Now the pointer to the current stored line list. + o_lp = PL_LP(pl,index) + o_pp = Ref (pl, o_lp) + if (o_pp == NULL) + return + + # Has the line been modified? + n_len = LL_LEN(ll) + if (n_len == LP_LEN(o_pp)) + if (pll_equal (ll, LL(pl,o_lp))) + return + + # Keep track of the number of edits. + PL_LLNUPDATES(pl) = PL_LLNUPDATES(pl) + 1 + + # Is the new line empty? + n_lp = PL_EMPTYLINE + n_pp = Ref (pl, n_lp) + if (n_len == LP_LEN(n_pp)) + if (pll_equal (ll, LL(pl,n_lp))) + goto update_ + + # Is the new line a copy of the adjacent line (Y=Y-1) in the image? + # Due to the short integer encoding a maximum of MAX_SHORT references + # are allowed per line. + + if (index > 1) { + n_lp = PL_LP(pl,index-1) + n_pp = Ref (pl, n_lp) + if (LP_NREF(n_pp) < MAX_SHORT) + if (n_len == LP_LEN(n_pp)) + if (pll_equal (ll, LL(pl,n_lp))) + goto update_ + } + + # The new line isn't a copy of the empty line or of an adjacent line, + # so copy it into the line list buffer. + + b_len = LP_BLEN(o_pp) + if (LP_NREF(o_pp) <= 1 && n_len <= b_len && o_lp != PL_EMPTYLINE) { + # Overwrite existing line. + + o_len = LP_LEN(o_pp) + call amovs (ll, LL(pl,o_lp), n_len) + LP_NREFS(o_pp) = 1 + LP_SETBLEN(o_pp, b_len) + PL_LLFREE(pl) = PL_LLFREE(pl) + (o_len - LP_LEN(o_pp)) + return + + } else { + # Add a new line. + + n_lp = pl_alloc (pl, n_len) + o_pp = Ref (pl, o_lp) + n_pp = Ref (pl, n_lp) + call amovs (ll, LL(pl,n_lp), n_len) + + LP_NREFS(n_pp) = 0 + LP_SETBLEN(n_pp, n_len) + PL_LLFREE(pl) = PL_LLFREE(pl) + n_len + } + + # We get here only if the new line has already been stored in the + # linelist buffer, with a pointer to such in N_LP, and a pointer to + # the old line in O_LP. Dereference the old line, which the new line + # is no longer associated with, and increase the reference count of + # the new line. +update_ + + # Dereference the old line and free the space if it is no longer used. + # If the old line buffer is freed we reclaim only LP_LEN words, since + # we already reclaimed LP_BLEN-LP_LEN in an earlier edit operation. + + LP_NREFS(o_pp) = LP_NREFS(o_pp) - 1 + if (LP_NREF(o_pp) == 0 && o_lp != PL_EMPTYLINE) + PL_LLFREE(pl) = PL_LLFREE(pl) + LP_LEN(o_pp) + + # Add another reference to the new line. + LP_NREFS(n_pp) = LP_NREFS(n_pp) + 1 + if (LP_NREF(n_pp) == 1 && n_lp != PL_EMPTYLINE) + PL_LLFREE(pl) = PL_LLFREE(pl) - LP_BLEN(n_pp) + + PL_LP(pl,index) = n_lp + return +oob_ + call syserr (SYS_PLREFOOB) +end diff --git a/sys/plio/plupolygon.x b/sys/plio/plupolygon.x new file mode 100644 index 00000000..b60e9bc5 --- /dev/null +++ b/sys/plio/plupolygon.x @@ -0,0 +1,223 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> +include "plpolygon.h" + + +# PL_UPOLYGON -- Regionrop ufcn for a general closed polygonal region. +# (surely there must be a simpler way to code this...) + +bool procedure pl_upolygon (ufd, line, rl_reg, xs, npix) + +pointer ufd #I user function descriptor +int line #I mask line number +int rl_reg[3,ARB] #O output range list for line Y +int xs #O start of edit region in dst mask +int npix #O number of pixels affected + +pointer xp, yp, pl +bool rl_new, cross +int nseg, np, low, rn, i1, i2, ii, i, j +int tempi, axlen, rl_len, p_prev, p_next +real tempr, y, y1, y2, x1, x2, p1, p2, p_y, n_y + +int btoi() +bool plr_equali() +define done_ 91 + +begin + pl = P_PL(ufd) + axlen = PL_AXLEN(pl,1) + rn = RL_FIRST + npix = 0 + xs = 1 + + nseg = P_NS(ufd) + xp = P_XP(ufd) + yp = P_YP(ufd) + y = real(line) + + # Find the point(s) of intersection of the current mask line with + # the line segments forming the polygon. Note that the line must + # cross a segment to go from inside to outside or vice versa; if a + # segment (or vertex) is merely touched it should be drawn, but it + # is not a point of crossing. + + do i = 1, nseg { + # Locate next and previous line segments. + if (i == 1) + p_prev = nseg + else + p_prev = i - 1 + if (i == nseg) + p_next = 1 + else + p_next = i + 2 + + # Get endpoints of current segment. + x1 = Memr[xp+i-1]; x2 = Memr[xp+i] + y1 = Memr[yp+i-1]; y2 = Memr[yp+i] + if (y1 > y2) { + swapr (x1, x2) + swapr (y1, y2) + swapi (p_next, p_prev) + } + + # Does current line intersect the polygon line segment? + if (y > y1-TOL && y < y2+TOL) { + p_y = Memr[yp+p_prev-1] + n_y = Memr[yp+p_next-1] + + if (y2 - y1 > TOL) { + # Single point of intersection. + p1 = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1) + p2 = p1 + + if (equal (p1, x1) && equal (y, y1)) + cross = ((p_y - y1) < 0) + else if (equal (p1, x2) && equal (y, y2)) + cross = ((n_y - y2) > 0) + else + cross = true + + } else { + # Intersection is entire line segment. + p1 = x1; p2 = x2 + cross = (((p_y - y) * (n_y - y)) < 0) + } + + i1 = max(1, min(axlen, nint(p1))) + i2 = max(1, min(axlen, nint(p2))) + if (i1 > i2) + swapi (i1, i2) + + np = i2 - i1 + 1 + if (np > 0) { + RL_X(rl_reg,rn) = i1 + RL_N(rl_reg,rn) = np + RL_V(rl_reg,rn) = btoi(cross) + rn = rn + 1 + } + } + } + + rl_len = rn - 1 + if (rl_len <= RL_FIRST) + goto done_ + + # Sort the line intersection-segments in order of increasing X. + do j = RL_FIRST, rl_len { + # Get low X value of initial segment. + i1 = RL_X(rl_reg,j) + np = RL_N(rl_reg,j) + i1 = min (i1, i1 + np - 1) + low = j + + # Find lowest valued segment in remainder of array. + do i = j+1, rl_len { + i2 = RL_X(rl_reg,i) + np = RL_N(rl_reg,i) + i2 = min (i2, i2 + np - 1) + if (i2 < i1) { + i1 = i2 + low = i + } + } + + # Interchange the initial segment and the low segment. + if (low != j) { + swapi (RL_X(rl_reg,j), RL_X(rl_reg,low)) + swapi (RL_N(rl_reg,j), RL_N(rl_reg,low)) + swapi (RL_V(rl_reg,j), RL_V(rl_reg,low)) + } + } + + # Combine any segments which overlap. + rn = RL_FIRST + do i = RL_FIRST + 1, rl_len { + i1 = RL_X(rl_reg,rn) + i2 = RL_N(rl_reg,rn) + i1 - 1 + ii = RL_X(rl_reg,i) + if (ii >= i1 && ii <= i2) { + i2 = ii + RL_N(rl_reg,i) - 1 + RL_N(rl_reg,rn) = max (RL_N(rl_reg,rn), i2 - i1 + 1) + RL_V(rl_reg,rn) = max (RL_V(rl_reg,rn), RL_V(rl_reg,i)) + } else { + rn = rn + 1 + RL_X(rl_reg,rn) = RL_X(rl_reg,i) + RL_N(rl_reg,rn) = RL_N(rl_reg,i) + RL_V(rl_reg,rn) = RL_V(rl_reg,i) + } + } + rl_len = rn + + # Now combine successive pairs of intersections to produce the line + # segments to be drawn. If all points are crossing points (where the + # image line crosses the polygon boundary) then we draw a line between + # the first two points, then the second two points, and so on. Points + # where the image line touches the polygon boundary but does not cross + # it are plotted, but are not joined with other points to make line + # segments. + + rn = RL_FIRST + ii = RL_FIRST + + do j = RL_FIRST, rl_len { + if (j <= ii && j < rl_len) { + next + + } else if (RL_V(rl_reg,ii) == YES) { + # Skip a vertext that touches but does not cross. + if (RL_V(rl_reg,j) == NO && j < rl_len) + next + + # Draw a line between the two crossing points. + RL_X(rl_reg,rn) = RL_X(rl_reg,ii) + RL_N(rl_reg,rn) = max (RL_N(rl_reg,ii), + RL_X(rl_reg,j) + RL_N(rl_reg,j) - RL_X(rl_reg,ii)) + RL_V(rl_reg,rn) = P_PV(ufd) + rn = rn + 1 + ii = j + 1 + + } else { + # Plot only the first point. + RL_X(rl_reg,rn) = RL_X(rl_reg,ii) + RL_N(rl_reg,rn) = RL_N(rl_reg,ii) + RL_V(rl_reg,rn) = P_PV(ufd) + rn = rn + 1 + + if (j >= rl_len && j != ii) { + # Plot the second point, if and end of list. + RL_X(rl_reg,rn) = RL_X(rl_reg,j) + RL_N(rl_reg,rn) = RL_N(rl_reg,j) + RL_V(rl_reg,rn) = P_PV(ufd) + rn = rn + 1 + } else + ii = j + } + } + +done_ + # Convert the X values in the range list to be relative to the start + # of the list. Compute NPIX, the range in pixels spanned by the range + # list. + + rl_len = rn - 1 + xs = RL_X(rl_reg,RL_FIRST) + npix = RL_X(rl_reg,rl_len) + RL_N(rl_reg,rl_len) - xs + + do i = RL_FIRST, rl_len + RL_X(rl_reg,i) = RL_X(rl_reg,i) - xs + 1 + + RL_LEN(rl_reg) = rl_len + RL_AXLEN(rl_reg) = npix + + rl_new = true + if (P_OY(ufd) == line - 1) + rl_new = !plr_equali (rl_reg, Memi[P_OO(ufd)]) + call amovi (rl_reg, Memi[P_OO(ufd)], rn - 1) + P_OY(ufd) = line + + return (rl_new) +end diff --git a/sys/plio/plvalid.x b/sys/plio/plvalid.x new file mode 100644 index 00000000..1d6482d9 --- /dev/null +++ b/sys/plio/plvalid.x @@ -0,0 +1,22 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <plio.h> + +# PLVALID -- Verify the validity of a mask descriptor. + +procedure plvalid (pl) + +pointer pl #I open mask descriptor +errchk syserr + +begin + if (pl != NULL) + if (PL_MAGIC(pl) == PL_MAGICVAL) + if (PL_LLBP(pl) == NULL) + call syserr (SYS_PLINACTDES) + else + return + + call syserr (SYS_PLINVDES) +end diff --git a/sys/plio/tf/mkpkg b/sys/plio/tf/mkpkg new file mode 100644 index 00000000..00a4d40e --- /dev/null +++ b/sys/plio/tf/mkpkg @@ -0,0 +1,51 @@ +# Update the type expanded generic files in the PLIO package library. + +$checkout libex.a lib$ +$update libex.a +$checkin libex.a lib$ +$exit + +libex.a: + plglpi.x <plio.h> + plglpl.x <plio.h> + plglps.x <plio.h> + plglri.x <plio.h> <plset.h> + plglrl.x <plio.h> <plset.h> + plglrs.x <plio.h> <plset.h> + pll2pi.x <plio.h> + pll2pl.x <plio.h> + pll2ps.x <plio.h> + pll2ri.x <plio.h> <plset.h> + pll2rl.x <plio.h> <plset.h> + pll2rs.x <plio.h> <plset.h> + plp2li.x <plio.h> + plp2ll.x <plio.h> + plp2ls.x <plio.h> + plp2ri.x <plio.h> <plset.h> + plp2rl.x <plio.h> <plset.h> + plp2rs.x <plio.h> <plset.h> + plplpi.x <plio.h> + plplpl.x <plio.h> + plplps.x <plio.h> + plplri.x <plio.h> + plplrl.x <plio.h> + plplrs.x <plio.h> + plpropi.x <plio.h> <plset.h> + plpropl.x <plio.h> <plset.h> + plprops.x <plio.h> <plset.h> + plr2li.x <plio.h> <plset.h> + plr2ll.x <plio.h> <plset.h> + plr2ls.x <plio.h> <plset.h> + plr2pi.x <plio.h> <plset.h> + plr2pl.x <plio.h> <plset.h> + plr2ps.x <plio.h> <plset.h> + plreqi.x <plset.h> + plreql.x <plset.h> + plreqs.x <plset.h> + plrpri.x <plio.h> <plset.h> + plrprl.x <plio.h> <plset.h> + plrprs.x <plio.h> <plset.h> + plrropi.x <plio.h> <plset.h> ../plrseg.h + plrropl.x <plio.h> <plset.h> ../plrseg.h + plrrops.x <plio.h> <plset.h> ../plrseg.h + ; diff --git a/sys/plio/tf/plglpi.x b/sys/plio/tf/plglpi.x new file mode 100644 index 00000000..3724ed6d --- /dev/null +++ b/sys/plio/tf/plglpi.x @@ -0,0 +1,38 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_GLP -- Get a line segment as a pixel array, applying the given ROP to +# combine the pixels with those of the output array. + +procedure pl_glpi (pl, v, px_dst, px_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +int px_dst[ARB] #O output pixel array +int px_depth #I pixel depth, bits +int npix #I number of pixels desired +int rop #I rasterop + +int np +pointer sp, px_out, ll_src +pointer pl_access() +int pl_l2pi() +errchk pl_access + +begin + ll_src = pl_access (pl,v) + if (!R_NEED_DST(rop)) { + np = pl_l2pi (Mems[ll_src], v[1], px_dst, npix) + return + } + + call smark (sp) + call salloc (px_out, npix, TY_INT) + + np = pl_l2pi (Mems[ll_src], v[1], Memi[px_out], npix) + call pl_pixropi (Memi[px_out], 1, PL_MAXVAL(pl), + px_dst, 1, MV(px_depth), npix, rop) + + call sfree (sp) +end diff --git a/sys/plio/tf/plglpl.x b/sys/plio/tf/plglpl.x new file mode 100644 index 00000000..6e1632c0 --- /dev/null +++ b/sys/plio/tf/plglpl.x @@ -0,0 +1,38 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_GLP -- Get a line segment as a pixel array, applying the given ROP to +# combine the pixels with those of the output array. + +procedure pl_glpl (pl, v, px_dst, px_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +long px_dst[ARB] #O output pixel array +int px_depth #I pixel depth, bits +int npix #I number of pixels desired +int rop #I rasterop + +int np +pointer sp, px_out, ll_src +pointer pl_access() +int pl_l2pl() +errchk pl_access + +begin + ll_src = pl_access (pl,v) + if (!R_NEED_DST(rop)) { + np = pl_l2pl (Mems[ll_src], v[1], px_dst, npix) + return + } + + call smark (sp) + call salloc (px_out, npix, TY_LONG) + + np = pl_l2pl (Mems[ll_src], v[1], Meml[px_out], npix) + call pl_pixropl (Meml[px_out], 1, PL_MAXVAL(pl), + px_dst, 1, MV(px_depth), npix, rop) + + call sfree (sp) +end diff --git a/sys/plio/tf/plglps.x b/sys/plio/tf/plglps.x new file mode 100644 index 00000000..728beb0a --- /dev/null +++ b/sys/plio/tf/plglps.x @@ -0,0 +1,38 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_GLP -- Get a line segment as a pixel array, applying the given ROP to +# combine the pixels with those of the output array. + +procedure pl_glps (pl, v, px_dst, px_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +short px_dst[ARB] #O output pixel array +int px_depth #I pixel depth, bits +int npix #I number of pixels desired +int rop #I rasterop + +int np +pointer sp, px_out, ll_src +pointer pl_access() +int pl_l2ps() +errchk pl_access + +begin + ll_src = pl_access (pl,v) + if (!R_NEED_DST(rop)) { + np = pl_l2ps (Mems[ll_src], v[1], px_dst, npix) + return + } + + call smark (sp) + call salloc (px_out, npix, TY_SHORT) + + np = pl_l2ps (Mems[ll_src], v[1], Mems[px_out], npix) + call pl_pixrops (Mems[px_out], 1, PL_MAXVAL(pl), + px_dst, 1, MV(px_depth), npix, rop) + + call sfree (sp) +end diff --git a/sys/plio/tf/plglri.x b/sys/plio/tf/plglri.x new file mode 100644 index 00000000..3f031ee5 --- /dev/null +++ b/sys/plio/tf/plglri.x @@ -0,0 +1,44 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> +include <plset.h> + +# PL_GLR -- Get a line segment as a range list, applying the given ROP to +# combine the pixels with those of the output list. + +procedure pl_glri (pl, v, rl_dst, rl_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +int rl_dst[ARB] #O output range list +int rl_depth #I range list depth, bits +int npix #I number of pixels desired +int rop #I rasterop + +int mr, nr +pointer sp, rl_out, rl_src, ll_src +pointer pl_access() +int pl_l2ri() +errchk pl_access + +begin + ll_src = pl_access (pl,v) + if (!R_NEED_DST(rop)) + nr = pl_l2ri (Mems[ll_src], v[1], rl_dst, npix) + else { + call smark (sp) + mr = min (RL_MAXLEN(pl), npix * 3) + call salloc (rl_src, mr, TY_INT) + call salloc (rl_out, mr, TY_INT) + + nr = pl_l2ri (Mems[ll_src], v[1], Memi[rl_src], npix) + call pl_rangeropi (Memi[rl_src], 1, PL_MAXVAL(pl), + rl_dst, 1, MV(rl_depth), + Memi[rl_out], npix, rop) + + # Copy out the edited range list. + call amovi (Memi[rl_out], rl_dst, RLI_LEN(rl_out)) + + call sfree (sp) + } +end diff --git a/sys/plio/tf/plglrl.x b/sys/plio/tf/plglrl.x new file mode 100644 index 00000000..cf30dc62 --- /dev/null +++ b/sys/plio/tf/plglrl.x @@ -0,0 +1,44 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> +include <plset.h> + +# PL_GLR -- Get a line segment as a range list, applying the given ROP to +# combine the pixels with those of the output list. + +procedure pl_glrl (pl, v, rl_dst, rl_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +long rl_dst[ARB] #O output range list +int rl_depth #I range list depth, bits +int npix #I number of pixels desired +int rop #I rasterop + +int mr, nr +pointer sp, rl_out, rl_src, ll_src +pointer pl_access() +int pl_l2rl() +errchk pl_access + +begin + ll_src = pl_access (pl,v) + if (!R_NEED_DST(rop)) + nr = pl_l2rl (Mems[ll_src], v[1], rl_dst, npix) + else { + call smark (sp) + mr = min (RL_MAXLEN(pl), npix * 3) + call salloc (rl_src, mr, TY_LONG) + call salloc (rl_out, mr, TY_LONG) + + nr = pl_l2rl (Mems[ll_src], v[1], Meml[rl_src], npix) + call pl_rangeropl (Meml[rl_src], 1, PL_MAXVAL(pl), + rl_dst, 1, MV(rl_depth), + Meml[rl_out], npix, rop) + + # Copy out the edited range list. + call amovl (Meml[rl_out], rl_dst, RLL_LEN(rl_out)) + + call sfree (sp) + } +end diff --git a/sys/plio/tf/plglrs.x b/sys/plio/tf/plglrs.x new file mode 100644 index 00000000..4c9c90a4 --- /dev/null +++ b/sys/plio/tf/plglrs.x @@ -0,0 +1,44 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> +include <plset.h> + +# PL_GLR -- Get a line segment as a range list, applying the given ROP to +# combine the pixels with those of the output list. + +procedure pl_glrs (pl, v, rl_dst, rl_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +short rl_dst[ARB] #O output range list +int rl_depth #I range list depth, bits +int npix #I number of pixels desired +int rop #I rasterop + +int mr, nr +pointer sp, rl_out, rl_src, ll_src +pointer pl_access() +int pl_l2rs() +errchk pl_access + +begin + ll_src = pl_access (pl,v) + if (!R_NEED_DST(rop)) + nr = pl_l2rs (Mems[ll_src], v[1], rl_dst, npix) + else { + call smark (sp) + mr = min (RL_MAXLEN(pl), npix * 3) + call salloc (rl_src, mr, TY_SHORT) + call salloc (rl_out, mr, TY_SHORT) + + nr = pl_l2rs (Mems[ll_src], v[1], Mems[rl_src], npix) + call pl_rangerops (Mems[rl_src], 1, PL_MAXVAL(pl), + rl_dst, 1, MV(rl_depth), + Mems[rl_out], npix, rop) + + # Copy out the edited range list. + call amovs (Mems[rl_out], rl_dst, RLS_LEN(rl_out)) + + call sfree (sp) + } +end diff --git a/sys/plio/tf/pll2pi.x b/sys/plio/tf/pll2pi.x new file mode 100644 index 00000000..cadea930 --- /dev/null +++ b/sys/plio/tf/pll2pi.x @@ -0,0 +1,105 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_L2P -- Convert a line list to a pixel array. The number of pixels output +# (always npix) is returned as the function value. + +int procedure pl_l2pi (ll_src, xs, px_dst, npix) + +short ll_src[ARB] #I input line list +int xs #I starting index in ll_src +int px_dst[ARB] #O output pixel array +int npix #I number of pixels to convert + +int pv +bool skipword +int opcode, data, ll_len, ll_first +int x1, x2, i1, i2, xe, np, ip, op, otop, i +define putpix_ 91 + +begin + # Support old format line lists. + if (LL_OLDFORMAT(ll_src)) { + ll_len = OLL_LEN(ll_src) + ll_first = OLL_FIRST + } else { + ll_len = LL_LEN(ll_src) + ll_first = LL_FIRST(ll_src) + } + + # No pixels? + if (npix <= 0 || ll_len <= 0) + return (0) + + xe = xs + npix - 1 + skipword = false + op = 1 + x1 = 1 + pv = 1 + + do ip = ll_first, ll_len { + if (skipword) { + skipword = false + next + } + + opcode = I_OPCODE(ll_src[ip]) + data = I_DATA(ll_src[ip]) + + switch (opcode) { + case I_ZN, I_HN, I_PN: + # Determine inbounds region of segment. + x2 = x1 + data - 1 + i1 = max (x1, xs) + i2 = min (x2, xe) + + # Process segment if any region is inbounds. + np = i2 - i1 + 1 + if (np > 0) { + otop = op + np - 1 + if (opcode == I_HN) { + do i = op, otop + px_dst[i] = pv + } else { + do i = op, otop + px_dst[i] = 0 + if (opcode == I_PN && i2 == x2) + px_dst[otop] = pv + } + op = otop + 1 + } + + # Advance the line index. + x1 = x2 + 1 + + case I_SH: + pv = (int(ll_src[ip+1]) * I_SHIFT) + data + skipword = true + case I_IH: + pv = pv + data + case I_DH: + pv = pv - data + case I_IS: + pv = pv + data + goto putpix_ + case I_DS: + pv = pv - data +putpix_ + if (x1 >= xs && x1 <= xe) { + px_dst[op] = pv + op = op + 1 + } + x1 = x1 + 1 + } + + if (x1 > xe) + break + } + + # Zero any remaining output range. + do i = op, npix + px_dst[i] = 0 + + return (npix) +end diff --git a/sys/plio/tf/pll2pl.x b/sys/plio/tf/pll2pl.x new file mode 100644 index 00000000..9863019b --- /dev/null +++ b/sys/plio/tf/pll2pl.x @@ -0,0 +1,105 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_L2P -- Convert a line list to a pixel array. The number of pixels output +# (always npix) is returned as the function value. + +int procedure pl_l2pl (ll_src, xs, px_dst, npix) + +short ll_src[ARB] #I input line list +int xs #I starting index in ll_src +long px_dst[ARB] #O output pixel array +int npix #I number of pixels to convert + +long pv +bool skipword +int opcode, data, ll_len, ll_first +int x1, x2, i1, i2, xe, np, ip, op, otop, i +define putpix_ 91 + +begin + # Support old format line lists. + if (LL_OLDFORMAT(ll_src)) { + ll_len = OLL_LEN(ll_src) + ll_first = OLL_FIRST + } else { + ll_len = LL_LEN(ll_src) + ll_first = LL_FIRST(ll_src) + } + + # No pixels? + if (npix <= 0 || ll_len <= 0) + return (0) + + xe = xs + npix - 1 + skipword = false + op = 1 + x1 = 1 + pv = 1 + + do ip = ll_first, ll_len { + if (skipword) { + skipword = false + next + } + + opcode = I_OPCODE(ll_src[ip]) + data = I_DATA(ll_src[ip]) + + switch (opcode) { + case I_ZN, I_HN, I_PN: + # Determine inbounds region of segment. + x2 = x1 + data - 1 + i1 = max (x1, xs) + i2 = min (x2, xe) + + # Process segment if any region is inbounds. + np = i2 - i1 + 1 + if (np > 0) { + otop = op + np - 1 + if (opcode == I_HN) { + do i = op, otop + px_dst[i] = pv + } else { + do i = op, otop + px_dst[i] = 0 + if (opcode == I_PN && i2 == x2) + px_dst[otop] = pv + } + op = otop + 1 + } + + # Advance the line index. + x1 = x2 + 1 + + case I_SH: + pv = (int(ll_src[ip+1]) * I_SHIFT) + data + skipword = true + case I_IH: + pv = pv + data + case I_DH: + pv = pv - data + case I_IS: + pv = pv + data + goto putpix_ + case I_DS: + pv = pv - data +putpix_ + if (x1 >= xs && x1 <= xe) { + px_dst[op] = pv + op = op + 1 + } + x1 = x1 + 1 + } + + if (x1 > xe) + break + } + + # Zero any remaining output range. + do i = op, npix + px_dst[i] = 0 + + return (npix) +end diff --git a/sys/plio/tf/pll2ps.x b/sys/plio/tf/pll2ps.x new file mode 100644 index 00000000..a853e5ba --- /dev/null +++ b/sys/plio/tf/pll2ps.x @@ -0,0 +1,105 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_L2P -- Convert a line list to a pixel array. The number of pixels output +# (always npix) is returned as the function value. + +int procedure pl_l2ps (ll_src, xs, px_dst, npix) + +short ll_src[ARB] #I input line list +int xs #I starting index in ll_src +short px_dst[ARB] #O output pixel array +int npix #I number of pixels to convert + +short pv +bool skipword +int opcode, data, ll_len, ll_first +int x1, x2, i1, i2, xe, np, ip, op, otop, i +define putpix_ 91 + +begin + # Support old format line lists. + if (LL_OLDFORMAT(ll_src)) { + ll_len = OLL_LEN(ll_src) + ll_first = OLL_FIRST + } else { + ll_len = LL_LEN(ll_src) + ll_first = LL_FIRST(ll_src) + } + + # No pixels? + if (npix <= 0 || ll_len <= 0) + return (0) + + xe = xs + npix - 1 + skipword = false + op = 1 + x1 = 1 + pv = 1 + + do ip = ll_first, ll_len { + if (skipword) { + skipword = false + next + } + + opcode = I_OPCODE(ll_src[ip]) + data = I_DATA(ll_src[ip]) + + switch (opcode) { + case I_ZN, I_HN, I_PN: + # Determine inbounds region of segment. + x2 = x1 + data - 1 + i1 = max (x1, xs) + i2 = min (x2, xe) + + # Process segment if any region is inbounds. + np = i2 - i1 + 1 + if (np > 0) { + otop = op + np - 1 + if (opcode == I_HN) { + do i = op, otop + px_dst[i] = pv + } else { + do i = op, otop + px_dst[i] = 0 + if (opcode == I_PN && i2 == x2) + px_dst[otop] = pv + } + op = otop + 1 + } + + # Advance the line index. + x1 = x2 + 1 + + case I_SH: + pv = (int(ll_src[ip+1]) * I_SHIFT) + data + skipword = true + case I_IH: + pv = pv + data + case I_DH: + pv = pv - data + case I_IS: + pv = pv + data + goto putpix_ + case I_DS: + pv = pv - data +putpix_ + if (x1 >= xs && x1 <= xe) { + px_dst[op] = pv + op = op + 1 + } + x1 = x1 + 1 + } + + if (x1 > xe) + break + } + + # Zero any remaining output range. + do i = op, npix + px_dst[i] = 0 + + return (npix) +end diff --git a/sys/plio/tf/pll2ri.x b/sys/plio/tf/pll2ri.x new file mode 100644 index 00000000..431b97e2 --- /dev/null +++ b/sys/plio/tf/pll2ri.x @@ -0,0 +1,117 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_L2R -- Convert a line list to a range list. The length of the output +# range list is returned as the function value. + +int procedure pl_l2ri (ll_src, xs, rl, npix) + +short ll_src[ARB] #I input line list +int xs #I starting index in ll_src +int rl[3,ARB] #O output range list +int npix #I number of pixels to convert + +int pv, hi +bool skipword +int opcode, data, ll_len, ll_first +int x1, x2, i1, i2, xe, np, rn, ip +define range_ 91 +define putrange_ 92 + +begin + # Support old format line lists. + if (LL_OLDFORMAT(ll_src)) { + ll_len = OLL_LEN(ll_src) + ll_first = OLL_FIRST + } else { + ll_len = LL_LEN(ll_src) + ll_first = LL_FIRST(ll_src) + } + + # No pixels? + if (npix <= 0 || ll_len <= 0) + return (0) + + rn = RL_FIRST + xe = xs + npix - 1 + skipword = false + x1 = 1 + hi = 1 + + do ip = ll_first, ll_len { + if (skipword) { + skipword = false + next + } + + opcode = I_OPCODE(ll_src[ip]) + data = I_DATA(ll_src[ip]) + + switch (opcode) { + case I_ZN: + pv = 0 + goto range_ + case I_HN: + pv = hi +range_ + # Determine inbounds region of segment. + x2 = x1 + data - 1 + i1 = max (x1, xs) + i2 = min (x2, xe) + np = i2 - i1 + 1 + x1 = x2 + 1 + + case I_PN: + pv = hi + x2 = x1 + data - 1 + if (x2 < xs || x2 > xe) + np = 0 + else { + i1 = x2 + np = 1 + } + x1 = x2 + 1 + + case I_SH: + hi = (int(ll_src[ip+1]) * I_SHIFT) + data + skipword = true + next + case I_IH: + hi = hi + data + next + case I_DH: + hi = hi - data + next + + case I_IS, I_DS: + if (opcode == I_IS) + hi = hi + data + else + hi = hi - data + + i1 = max (x1, xs) + i2 = min (x1, xe) + np = i2 - i1 + 1 + x1 = x1 + 1 + pv = hi + } + + # Output a range entry? + if (np > 0 && pv > 0) { + rl[1,rn] = i1 + rl[2,rn] = np + rl[3,rn] = pv + rn = rn + 1 + } + + if (x1 > xe) + break + } + + RL_LEN(rl) = rn - 1 + RL_AXLEN(rl) = npix + + return (rn - 1) +end diff --git a/sys/plio/tf/pll2rl.x b/sys/plio/tf/pll2rl.x new file mode 100644 index 00000000..0ff4ce4b --- /dev/null +++ b/sys/plio/tf/pll2rl.x @@ -0,0 +1,117 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_L2R -- Convert a line list to a range list. The length of the output +# range list is returned as the function value. + +int procedure pl_l2rl (ll_src, xs, rl, npix) + +short ll_src[ARB] #I input line list +int xs #I starting index in ll_src +long rl[3,ARB] #O output range list +int npix #I number of pixels to convert + +int pv, hi +bool skipword +int opcode, data, ll_len, ll_first +int x1, x2, i1, i2, xe, np, rn, ip +define range_ 91 +define putrange_ 92 + +begin + # Support old format line lists. + if (LL_OLDFORMAT(ll_src)) { + ll_len = OLL_LEN(ll_src) + ll_first = OLL_FIRST + } else { + ll_len = LL_LEN(ll_src) + ll_first = LL_FIRST(ll_src) + } + + # No pixels? + if (npix <= 0 || ll_len <= 0) + return (0) + + rn = RL_FIRST + xe = xs + npix - 1 + skipword = false + x1 = 1 + hi = 1 + + do ip = ll_first, ll_len { + if (skipword) { + skipword = false + next + } + + opcode = I_OPCODE(ll_src[ip]) + data = I_DATA(ll_src[ip]) + + switch (opcode) { + case I_ZN: + pv = 0 + goto range_ + case I_HN: + pv = hi +range_ + # Determine inbounds region of segment. + x2 = x1 + data - 1 + i1 = max (x1, xs) + i2 = min (x2, xe) + np = i2 - i1 + 1 + x1 = x2 + 1 + + case I_PN: + pv = hi + x2 = x1 + data - 1 + if (x2 < xs || x2 > xe) + np = 0 + else { + i1 = x2 + np = 1 + } + x1 = x2 + 1 + + case I_SH: + hi = (int(ll_src[ip+1]) * I_SHIFT) + data + skipword = true + next + case I_IH: + hi = hi + data + next + case I_DH: + hi = hi - data + next + + case I_IS, I_DS: + if (opcode == I_IS) + hi = hi + data + else + hi = hi - data + + i1 = max (x1, xs) + i2 = min (x1, xe) + np = i2 - i1 + 1 + x1 = x1 + 1 + pv = hi + } + + # Output a range entry? + if (np > 0 && pv > 0) { + rl[1,rn] = i1 + rl[2,rn] = np + rl[3,rn] = pv + rn = rn + 1 + } + + if (x1 > xe) + break + } + + RL_LEN(rl) = rn - 1 + RL_AXLEN(rl) = npix + + return (rn - 1) +end diff --git a/sys/plio/tf/pll2rs.x b/sys/plio/tf/pll2rs.x new file mode 100644 index 00000000..a0852774 --- /dev/null +++ b/sys/plio/tf/pll2rs.x @@ -0,0 +1,117 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_L2R -- Convert a line list to a range list. The length of the output +# range list is returned as the function value. + +int procedure pl_l2rs (ll_src, xs, rl, npix) + +short ll_src[ARB] #I input line list +int xs #I starting index in ll_src +short rl[3,ARB] #O output range list +int npix #I number of pixels to convert + +int pv, hi +bool skipword +int opcode, data, ll_len, ll_first +int x1, x2, i1, i2, xe, np, rn, ip +define range_ 91 +define putrange_ 92 + +begin + # Support old format line lists. + if (LL_OLDFORMAT(ll_src)) { + ll_len = OLL_LEN(ll_src) + ll_first = OLL_FIRST + } else { + ll_len = LL_LEN(ll_src) + ll_first = LL_FIRST(ll_src) + } + + # No pixels? + if (npix <= 0 || ll_len <= 0) + return (0) + + rn = RL_FIRST + xe = xs + npix - 1 + skipword = false + x1 = 1 + hi = 1 + + do ip = ll_first, ll_len { + if (skipword) { + skipword = false + next + } + + opcode = I_OPCODE(ll_src[ip]) + data = I_DATA(ll_src[ip]) + + switch (opcode) { + case I_ZN: + pv = 0 + goto range_ + case I_HN: + pv = hi +range_ + # Determine inbounds region of segment. + x2 = x1 + data - 1 + i1 = max (x1, xs) + i2 = min (x2, xe) + np = i2 - i1 + 1 + x1 = x2 + 1 + + case I_PN: + pv = hi + x2 = x1 + data - 1 + if (x2 < xs || x2 > xe) + np = 0 + else { + i1 = x2 + np = 1 + } + x1 = x2 + 1 + + case I_SH: + hi = (int(ll_src[ip+1]) * I_SHIFT) + data + skipword = true + next + case I_IH: + hi = hi + data + next + case I_DH: + hi = hi - data + next + + case I_IS, I_DS: + if (opcode == I_IS) + hi = hi + data + else + hi = hi - data + + i1 = max (x1, xs) + i2 = min (x1, xe) + np = i2 - i1 + 1 + x1 = x1 + 1 + pv = hi + } + + # Output a range entry? + if (np > 0 && pv > 0) { + rl[1,rn] = i1 + rl[2,rn] = np + rl[3,rn] = pv + rn = rn + 1 + } + + if (x1 > xe) + break + } + + RL_LEN(rl) = rn - 1 + RL_AXLEN(rl) = npix + + return (rn - 1) +end diff --git a/sys/plio/tf/plp2li.x b/sys/plio/tf/plp2li.x new file mode 100644 index 00000000..58b3a8b5 --- /dev/null +++ b/sys/plio/tf/plp2li.x @@ -0,0 +1,126 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_P2L -- Convert a pixel array to a line list. The length of the list is +# returned as the function value. + +int procedure pl_p2li (px_src, xs, ll_dst, npix) + +int px_src[ARB] #I input pixel array +int xs #I starting index in pixbuf +short ll_dst[ARB] #O destination line list +int npix #I number of pixels to convert + +int hi, pv, nv, zero +int xe, x1, iz, ip, op, np, nz, dv, v +define done_ 91 + +begin + # No input pixels? + if (npix <= 0) + return (0) + + # Initialize the linelist header. + LL_VERSION(ll_dst) = LL_CURVERSION + LL_HDRLEN(ll_dst) = LL_CURHDRLEN + LL_NREFS(ll_dst) = 0 + LL_SETBLEN(ll_dst,0) + + xe = xs + npix - 1 + op = LL_CURHDRLEN + 1 + + # Pack the pixel array into a line list. This is done by scanning + # the pixel list for successive ranges of pixels of constant nonzero + # value, where each range is described as follows: + + zero = 0 + pv = max (zero, px_src[xs]) # pixel value of current range + x1 = xs # start index of current range + iz = xs # start index of range of zeros + hi = 1 # current high value + + # Process the data array. + do ip = xs, xe { + if (ip < xe) { + # Get the next pixel value, loop again if same as previous one. + nv = max (zero, px_src[ip+1]) + if (nv == pv) + next + + # If current range is zero, loop again to get nonzero range. + if (pv == 0) { + pv = nv + x1 = ip + 1 + next + } + } else if (pv == 0) + x1 = xe + 1 + + # Encode an instruction to regenerate the current range I0-IP + # of N data values of nonzero level PV. In the most complex case + # we must update the high value and output a range of zeros, + # followed by a range of NP high values. If NP is 1, we can + # probably use a PN or [ID]S instruction to save space. + + np = ip - x1 + 1 + nz = x1 - iz + + # Change the high value? + if (pv > 0) { + dv = pv - hi + if (dv != 0) { + # Output IH or DH instruction? + hi = pv + if (abs(dv) > I_DATAMAX) { + ll_dst[op] = M_SH + and (int(pv), I_DATAMAX) + op = op + 1 + ll_dst[op] = pv / I_SHIFT + op = op + 1 + } else { + if (dv < 0) + ll_dst[op] = M_DH + (-dv) + else + ll_dst[op] = M_IH + dv + op = op + 1 + + # Convert to IS or DS if range is a single pixel. + if (np == 1 && nz == 0) { + v = ll_dst[op-1] + ll_dst[op-1] = or (v, M_MOVE) + goto done_ + } + } + } + } + + # Output range of zeros to catch up to current range? + # The I_DATAMAX-1 limit is to allow adding M_PN+1 without + # overflowing the range of the data segment. + if (nz > 0) { + # Output the ZN instruction. + for (; nz > 0; nz = nz - (I_DATAMAX-1)) { + ll_dst[op] = M_ZN + min(I_DATAMAX-1,nz) + op = op + 1 + } + # Convert to PN if range is a single pixel. + if (np == 1 && pv > 0) { + ll_dst[op-1] = ll_dst[op-1] + M_PN + 1 + goto done_ + } + } + + # The only thing left is the HN instruction if we get here. + for (; np > 0; np = np - I_DATAMAX) { + ll_dst[op] = M_HN + min(I_DATAMAX,np) + op = op + 1 + } +done_ + x1 = ip + 1 + iz = x1 + pv = nv + } + + LL_SETLEN(ll_dst, op - 1) + return (op - 1) +end diff --git a/sys/plio/tf/plp2ll.x b/sys/plio/tf/plp2ll.x new file mode 100644 index 00000000..fa4a7d13 --- /dev/null +++ b/sys/plio/tf/plp2ll.x @@ -0,0 +1,126 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_P2L -- Convert a pixel array to a line list. The length of the list is +# returned as the function value. + +int procedure pl_p2ll (px_src, xs, ll_dst, npix) + +long px_src[ARB] #I input pixel array +int xs #I starting index in pixbuf +short ll_dst[ARB] #O destination line list +int npix #I number of pixels to convert + +long hi, pv, nv, zero +int xe, x1, iz, ip, op, np, nz, dv, v +define done_ 91 + +begin + # No input pixels? + if (npix <= 0) + return (0) + + # Initialize the linelist header. + LL_VERSION(ll_dst) = LL_CURVERSION + LL_HDRLEN(ll_dst) = LL_CURHDRLEN + LL_NREFS(ll_dst) = 0 + LL_SETBLEN(ll_dst,0) + + xe = xs + npix - 1 + op = LL_CURHDRLEN + 1 + + # Pack the pixel array into a line list. This is done by scanning + # the pixel list for successive ranges of pixels of constant nonzero + # value, where each range is described as follows: + + zero = 0 + pv = max (zero, px_src[xs]) # pixel value of current range + x1 = xs # start index of current range + iz = xs # start index of range of zeros + hi = 1 # current high value + + # Process the data array. + do ip = xs, xe { + if (ip < xe) { + # Get the next pixel value, loop again if same as previous one. + nv = max (zero, px_src[ip+1]) + if (nv == pv) + next + + # If current range is zero, loop again to get nonzero range. + if (pv == 0) { + pv = nv + x1 = ip + 1 + next + } + } else if (pv == 0) + x1 = xe + 1 + + # Encode an instruction to regenerate the current range I0-IP + # of N data values of nonzero level PV. In the most complex case + # we must update the high value and output a range of zeros, + # followed by a range of NP high values. If NP is 1, we can + # probably use a PN or [ID]S instruction to save space. + + np = ip - x1 + 1 + nz = x1 - iz + + # Change the high value? + if (pv > 0) { + dv = pv - hi + if (dv != 0) { + # Output IH or DH instruction? + hi = pv + if (abs(dv) > I_DATAMAX) { + ll_dst[op] = M_SH + and (int(pv), I_DATAMAX) + op = op + 1 + ll_dst[op] = pv / I_SHIFT + op = op + 1 + } else { + if (dv < 0) + ll_dst[op] = M_DH + (-dv) + else + ll_dst[op] = M_IH + dv + op = op + 1 + + # Convert to IS or DS if range is a single pixel. + if (np == 1 && nz == 0) { + v = ll_dst[op-1] + ll_dst[op-1] = or (v, M_MOVE) + goto done_ + } + } + } + } + + # Output range of zeros to catch up to current range? + # The I_DATAMAX-1 limit is to allow adding M_PN+1 without + # overflowing the range of the data segment. + if (nz > 0) { + # Output the ZN instruction. + for (; nz > 0; nz = nz - (I_DATAMAX-1)) { + ll_dst[op] = M_ZN + min(I_DATAMAX-1,nz) + op = op + 1 + } + # Convert to PN if range is a single pixel. + if (np == 1 && pv > 0) { + ll_dst[op-1] = ll_dst[op-1] + M_PN + 1 + goto done_ + } + } + + # The only thing left is the HN instruction if we get here. + for (; np > 0; np = np - I_DATAMAX) { + ll_dst[op] = M_HN + min(I_DATAMAX,np) + op = op + 1 + } +done_ + x1 = ip + 1 + iz = x1 + pv = nv + } + + LL_SETLEN(ll_dst, op - 1) + return (op - 1) +end diff --git a/sys/plio/tf/plp2ls.x b/sys/plio/tf/plp2ls.x new file mode 100644 index 00000000..327778dc --- /dev/null +++ b/sys/plio/tf/plp2ls.x @@ -0,0 +1,126 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_P2L -- Convert a pixel array to a line list. The length of the list is +# returned as the function value. + +int procedure pl_p2ls (px_src, xs, ll_dst, npix) + +short px_src[ARB] #I input pixel array +int xs #I starting index in pixbuf +short ll_dst[ARB] #O destination line list +int npix #I number of pixels to convert + +short hi, pv, nv, zero +int xe, x1, iz, ip, op, np, nz, dv, v +define done_ 91 + +begin + # No input pixels? + if (npix <= 0) + return (0) + + # Initialize the linelist header. + LL_VERSION(ll_dst) = LL_CURVERSION + LL_HDRLEN(ll_dst) = LL_CURHDRLEN + LL_NREFS(ll_dst) = 0 + LL_SETBLEN(ll_dst,0) + + xe = xs + npix - 1 + op = LL_CURHDRLEN + 1 + + # Pack the pixel array into a line list. This is done by scanning + # the pixel list for successive ranges of pixels of constant nonzero + # value, where each range is described as follows: + + zero = 0 + pv = max (zero, px_src[xs]) # pixel value of current range + x1 = xs # start index of current range + iz = xs # start index of range of zeros + hi = 1 # current high value + + # Process the data array. + do ip = xs, xe { + if (ip < xe) { + # Get the next pixel value, loop again if same as previous one. + nv = max (zero, px_src[ip+1]) + if (nv == pv) + next + + # If current range is zero, loop again to get nonzero range. + if (pv == 0) { + pv = nv + x1 = ip + 1 + next + } + } else if (pv == 0) + x1 = xe + 1 + + # Encode an instruction to regenerate the current range I0-IP + # of N data values of nonzero level PV. In the most complex case + # we must update the high value and output a range of zeros, + # followed by a range of NP high values. If NP is 1, we can + # probably use a PN or [ID]S instruction to save space. + + np = ip - x1 + 1 + nz = x1 - iz + + # Change the high value? + if (pv > 0) { + dv = pv - hi + if (dv != 0) { + # Output IH or DH instruction? + hi = pv + if (abs(dv) > I_DATAMAX) { + ll_dst[op] = M_SH + and (int(pv), I_DATAMAX) + op = op + 1 + ll_dst[op] = pv / I_SHIFT + op = op + 1 + } else { + if (dv < 0) + ll_dst[op] = M_DH + (-dv) + else + ll_dst[op] = M_IH + dv + op = op + 1 + + # Convert to IS or DS if range is a single pixel. + if (np == 1 && nz == 0) { + v = ll_dst[op-1] + ll_dst[op-1] = or (v, M_MOVE) + goto done_ + } + } + } + } + + # Output range of zeros to catch up to current range? + # The I_DATAMAX-1 limit is to allow adding M_PN+1 without + # overflowing the range of the data segment. + if (nz > 0) { + # Output the ZN instruction. + for (; nz > 0; nz = nz - (I_DATAMAX-1)) { + ll_dst[op] = M_ZN + min(I_DATAMAX-1,nz) + op = op + 1 + } + # Convert to PN if range is a single pixel. + if (np == 1 && pv > 0) { + ll_dst[op-1] = ll_dst[op-1] + M_PN + 1 + goto done_ + } + } + + # The only thing left is the HN instruction if we get here. + for (; np > 0; np = np - I_DATAMAX) { + ll_dst[op] = M_HN + min(I_DATAMAX,np) + op = op + 1 + } +done_ + x1 = ip + 1 + iz = x1 + pv = nv + } + + LL_SETLEN(ll_dst, op - 1) + return (op - 1) +end diff --git a/sys/plio/tf/plp2ri.x b/sys/plio/tf/plp2ri.x new file mode 100644 index 00000000..64f4f1eb --- /dev/null +++ b/sys/plio/tf/plp2ri.x @@ -0,0 +1,71 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_P2R -- Convert a pixel array to a range list. The length of the output +# range list is returned as the function value. + +int procedure pl_p2ri (px_src, xs, rl, npix) + +int px_src[ARB] #I input pixel array +int xs #I starting index in pixbuf +int rl[3,ARB] #O destination range list +int npix #I number of pixels to convert + +int hi, pv, zero +int xe, x1, np, rn, nv, ip +define done_ 91 + +begin + # No input pixels? + if (npix <= 0) + return (0) + + xe = xs + npix - 1 + rn = RL_FIRST + + # Pack the pixel array into a range list. This is done by scanning + # the pixel list for successive ranges of pixels of constant nonzero + # value, where each range is described as follows: + + zero = 0 + pv = max (zero, px_src[xs]) # pixel value of current range + x1 = xs # start index of current range + hi = 1 # current high value + + # Process the data array. + do ip = xs, xe { + if (ip < xe) { + # Get the next pixel value, loop again if same as previous one. + nv = max (zero, px_src[ip+1]) + if (nv == pv) + next + + # If current range is zero, loop again to get nonzero range. + if (pv == 0) { + pv = nv + x1 = ip + 1 + next + } + } + + np = ip - x1 + 1 + + # Output the new range. + if (pv > 0) { + rl[1,rn] = x1 + rl[2,rn] = np + rl[3,rn] = pv + rn = rn + 1 + } + + x1 = ip + 1 + pv = nv + } + + RL_LEN(rl) = rn - 1 + RL_AXLEN(rl) = npix + + return (rn - 1) +end diff --git a/sys/plio/tf/plp2rl.x b/sys/plio/tf/plp2rl.x new file mode 100644 index 00000000..574faad9 --- /dev/null +++ b/sys/plio/tf/plp2rl.x @@ -0,0 +1,71 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_P2R -- Convert a pixel array to a range list. The length of the output +# range list is returned as the function value. + +int procedure pl_p2rl (px_src, xs, rl, npix) + +long px_src[ARB] #I input pixel array +int xs #I starting index in pixbuf +long rl[3,ARB] #O destination range list +int npix #I number of pixels to convert + +long hi, pv, zero +int xe, x1, np, rn, nv, ip +define done_ 91 + +begin + # No input pixels? + if (npix <= 0) + return (0) + + xe = xs + npix - 1 + rn = RL_FIRST + + # Pack the pixel array into a range list. This is done by scanning + # the pixel list for successive ranges of pixels of constant nonzero + # value, where each range is described as follows: + + zero = 0 + pv = max (zero, px_src[xs]) # pixel value of current range + x1 = xs # start index of current range + hi = 1 # current high value + + # Process the data array. + do ip = xs, xe { + if (ip < xe) { + # Get the next pixel value, loop again if same as previous one. + nv = max (zero, px_src[ip+1]) + if (nv == pv) + next + + # If current range is zero, loop again to get nonzero range. + if (pv == 0) { + pv = nv + x1 = ip + 1 + next + } + } + + np = ip - x1 + 1 + + # Output the new range. + if (pv > 0) { + rl[1,rn] = x1 + rl[2,rn] = np + rl[3,rn] = pv + rn = rn + 1 + } + + x1 = ip + 1 + pv = nv + } + + RL_LEN(rl) = rn - 1 + RL_AXLEN(rl) = npix + + return (rn - 1) +end diff --git a/sys/plio/tf/plp2rs.x b/sys/plio/tf/plp2rs.x new file mode 100644 index 00000000..da082f47 --- /dev/null +++ b/sys/plio/tf/plp2rs.x @@ -0,0 +1,71 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_P2R -- Convert a pixel array to a range list. The length of the output +# range list is returned as the function value. + +int procedure pl_p2rs (px_src, xs, rl, npix) + +short px_src[ARB] #I input pixel array +int xs #I starting index in pixbuf +short rl[3,ARB] #O destination range list +int npix #I number of pixels to convert + +short hi, pv, zero +int xe, x1, np, rn, nv, ip +define done_ 91 + +begin + # No input pixels? + if (npix <= 0) + return (0) + + xe = xs + npix - 1 + rn = RL_FIRST + + # Pack the pixel array into a range list. This is done by scanning + # the pixel list for successive ranges of pixels of constant nonzero + # value, where each range is described as follows: + + zero = 0 + pv = max (zero, px_src[xs]) # pixel value of current range + x1 = xs # start index of current range + hi = 1 # current high value + + # Process the data array. + do ip = xs, xe { + if (ip < xe) { + # Get the next pixel value, loop again if same as previous one. + nv = max (zero, px_src[ip+1]) + if (nv == pv) + next + + # If current range is zero, loop again to get nonzero range. + if (pv == 0) { + pv = nv + x1 = ip + 1 + next + } + } + + np = ip - x1 + 1 + + # Output the new range. + if (pv > 0) { + rl[1,rn] = x1 + rl[2,rn] = np + rl[3,rn] = pv + rn = rn + 1 + } + + x1 = ip + 1 + pv = nv + } + + RL_LEN(rl) = rn - 1 + RL_AXLEN(rl) = npix + + return (rn - 1) +end diff --git a/sys/plio/tf/plplpi.x b/sys/plio/tf/plplpi.x new file mode 100644 index 00000000..26c094d4 --- /dev/null +++ b/sys/plio/tf/plplpi.x @@ -0,0 +1,41 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_PLP -- Put a line segment input as a pixel array to a mask, applying the +# given ROP to combine the line segment with the existing line of the mask. + +procedure pl_plpi (pl, v, px_src, px_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +int px_src[ARB] #I input pixel array +int px_depth #I pixel depth, bits +int npix #I number of pixels to be set +int rop #I rasterop + +int ll_len +pointer sp, ll_src, ll_out, ll_dst +pointer pl_access() +int pl_p2li() +errchk pl_access + +begin + call smark (sp) + call salloc (ll_src, LL_MAXLEN(pl), TY_SHORT) + + # Convert the pixel array to a line list. + ll_len = pl_p2li (px_src, 1, Mems[ll_src], npix) + + if (!R_NEED_DST(rop) && v[1] == 1 && npix == PL_AXLEN(pl,1)) + call pl_update (pl, v, Mems[ll_src]) + else { + call salloc (ll_out, LL_MAXLEN(pl), TY_SHORT) + ll_dst = pl_access (pl,v) + call pl_linerop (Mems[ll_src], 1, PL_MAXVAL(pl), Mems[ll_dst], v[1], + MV(px_depth), Mems[ll_out], npix, rop) + call pl_update (pl, v, Mems[ll_out]) + } + + call sfree (sp) +end diff --git a/sys/plio/tf/plplpl.x b/sys/plio/tf/plplpl.x new file mode 100644 index 00000000..85a11304 --- /dev/null +++ b/sys/plio/tf/plplpl.x @@ -0,0 +1,41 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_PLP -- Put a line segment input as a pixel array to a mask, applying the +# given ROP to combine the line segment with the existing line of the mask. + +procedure pl_plpl (pl, v, px_src, px_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +long px_src[ARB] #I input pixel array +int px_depth #I pixel depth, bits +int npix #I number of pixels to be set +int rop #I rasterop + +int ll_len +pointer sp, ll_src, ll_out, ll_dst +pointer pl_access() +int pl_p2ll() +errchk pl_access + +begin + call smark (sp) + call salloc (ll_src, LL_MAXLEN(pl), TY_SHORT) + + # Convert the pixel array to a line list. + ll_len = pl_p2ll (px_src, 1, Mems[ll_src], npix) + + if (!R_NEED_DST(rop) && v[1] == 1 && npix == PL_AXLEN(pl,1)) + call pl_update (pl, v, Mems[ll_src]) + else { + call salloc (ll_out, LL_MAXLEN(pl), TY_SHORT) + ll_dst = pl_access (pl,v) + call pl_linerop (Mems[ll_src], 1, PL_MAXVAL(pl), Mems[ll_dst], v[1], + MV(px_depth), Mems[ll_out], npix, rop) + call pl_update (pl, v, Mems[ll_out]) + } + + call sfree (sp) +end diff --git a/sys/plio/tf/plplps.x b/sys/plio/tf/plplps.x new file mode 100644 index 00000000..b693c90e --- /dev/null +++ b/sys/plio/tf/plplps.x @@ -0,0 +1,41 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_PLP -- Put a line segment input as a pixel array to a mask, applying the +# given ROP to combine the line segment with the existing line of the mask. + +procedure pl_plps (pl, v, px_src, px_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +short px_src[ARB] #I input pixel array +int px_depth #I pixel depth, bits +int npix #I number of pixels to be set +int rop #I rasterop + +int ll_len +pointer sp, ll_src, ll_out, ll_dst +pointer pl_access() +int pl_p2ls() +errchk pl_access + +begin + call smark (sp) + call salloc (ll_src, LL_MAXLEN(pl), TY_SHORT) + + # Convert the pixel array to a line list. + ll_len = pl_p2ls (px_src, 1, Mems[ll_src], npix) + + if (!R_NEED_DST(rop) && v[1] == 1 && npix == PL_AXLEN(pl,1)) + call pl_update (pl, v, Mems[ll_src]) + else { + call salloc (ll_out, LL_MAXLEN(pl), TY_SHORT) + ll_dst = pl_access (pl,v) + call pl_linerop (Mems[ll_src], 1, PL_MAXVAL(pl), Mems[ll_dst], v[1], + MV(px_depth), Mems[ll_out], npix, rop) + call pl_update (pl, v, Mems[ll_out]) + } + + call sfree (sp) +end diff --git a/sys/plio/tf/plplri.x b/sys/plio/tf/plplri.x new file mode 100644 index 00000000..433f9a88 --- /dev/null +++ b/sys/plio/tf/plplri.x @@ -0,0 +1,41 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_PLR -- Put a line segment input as a range list to a mask, applying the +# given ROP to combine the line segment with the existing line of the mask. + +procedure pl_plri (pl, v, rl_src, rl_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +int rl_src[ARB] #I input range list +int rl_depth #I range list depth, bits +int npix #I number of pixels to be set +int rop #I rasterop + +int ll_len +pointer sp, ll_src, ll_out, ll_dst +pointer pl_access() +int pl_r2li() +errchk pl_access + +begin + call smark (sp) + call salloc (ll_src, LL_MAXLEN(pl), TY_SHORT) + + # Convert the range list to a line list. + ll_len = pl_r2li (rl_src, 1, Mems[ll_src], npix) + + if (!R_NEED_DST(rop) && v[1] == 1 && npix == PL_AXLEN(pl,1)) + call pl_update (pl, v, Mems[ll_src]) + else { + call salloc (ll_out, LL_MAXLEN(pl), TY_SHORT) + ll_dst = pl_access (pl,v) + call pl_linerop (Mems[ll_src], 1, PL_MAXVAL(pl), Mems[ll_dst], v[1], + MV(rl_depth), Mems[ll_out], npix, rop) + call pl_update (pl, v, Mems[ll_out]) + } + + call sfree (sp) +end diff --git a/sys/plio/tf/plplrl.x b/sys/plio/tf/plplrl.x new file mode 100644 index 00000000..bf40b9ef --- /dev/null +++ b/sys/plio/tf/plplrl.x @@ -0,0 +1,41 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_PLR -- Put a line segment input as a range list to a mask, applying the +# given ROP to combine the line segment with the existing line of the mask. + +procedure pl_plrl (pl, v, rl_src, rl_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +long rl_src[ARB] #I input range list +int rl_depth #I range list depth, bits +int npix #I number of pixels to be set +int rop #I rasterop + +int ll_len +pointer sp, ll_src, ll_out, ll_dst +pointer pl_access() +int pl_r2ll() +errchk pl_access + +begin + call smark (sp) + call salloc (ll_src, LL_MAXLEN(pl), TY_SHORT) + + # Convert the range list to a line list. + ll_len = pl_r2ll (rl_src, 1, Mems[ll_src], npix) + + if (!R_NEED_DST(rop) && v[1] == 1 && npix == PL_AXLEN(pl,1)) + call pl_update (pl, v, Mems[ll_src]) + else { + call salloc (ll_out, LL_MAXLEN(pl), TY_SHORT) + ll_dst = pl_access (pl,v) + call pl_linerop (Mems[ll_src], 1, PL_MAXVAL(pl), Mems[ll_dst], v[1], + MV(rl_depth), Mems[ll_out], npix, rop) + call pl_update (pl, v, Mems[ll_out]) + } + + call sfree (sp) +end diff --git a/sys/plio/tf/plplrs.x b/sys/plio/tf/plplrs.x new file mode 100644 index 00000000..13318070 --- /dev/null +++ b/sys/plio/tf/plplrs.x @@ -0,0 +1,41 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_PLR -- Put a line segment input as a range list to a mask, applying the +# given ROP to combine the line segment with the existing line of the mask. + +procedure pl_plrs (pl, v, rl_src, rl_depth, npix, rop) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I vector coords of line segment +short rl_src[ARB] #I input range list +int rl_depth #I range list depth, bits +int npix #I number of pixels to be set +int rop #I rasterop + +int ll_len +pointer sp, ll_src, ll_out, ll_dst +pointer pl_access() +int pl_r2ls() +errchk pl_access + +begin + call smark (sp) + call salloc (ll_src, LL_MAXLEN(pl), TY_SHORT) + + # Convert the range list to a line list. + ll_len = pl_r2ls (rl_src, 1, Mems[ll_src], npix) + + if (!R_NEED_DST(rop) && v[1] == 1 && npix == PL_AXLEN(pl,1)) + call pl_update (pl, v, Mems[ll_src]) + else { + call salloc (ll_out, LL_MAXLEN(pl), TY_SHORT) + ll_dst = pl_access (pl,v) + call pl_linerop (Mems[ll_src], 1, PL_MAXVAL(pl), Mems[ll_dst], v[1], + MV(rl_depth), Mems[ll_out], npix, rop) + call pl_update (pl, v, Mems[ll_out]) + } + + call sfree (sp) +end diff --git a/sys/plio/tf/plpropi.x b/sys/plio/tf/plpropi.x new file mode 100644 index 00000000..ecfe7227 --- /dev/null +++ b/sys/plio/tf/plpropi.x @@ -0,0 +1,177 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_PIXROP -- Rasterop between source and destination pixel arrays. + +procedure pl_pixropi (px_src,xs,src_maxval, px_dst,ds,dst_maxval, npix, rop) + +int px_src[ARB] #I source pixel array +int xs #I starting pixel index in src +int src_maxval #I max pixel value in src mask +int px_dst[ARB] #O destination pixel array +int ds #I starting pixel index in dst +int dst_maxval #I max pixel value in dst mask +int npix #I number of pixels to convert +int rop #I rasterop + +pointer sp, src +int opcode, i +int data, ceil, src_value +int and(), or(), xor(), not() +define out_ 91 + +begin + opcode = R_OPCODE(rop) + data = R_DATA(rop) + ceil = 0 + + # Pixel value to be used if input mask is boolean. + if (src_maxval == 1) { + src_value = data + if (src_value <= 0) + src_value = dst_maxval + } + + # Handle the easy cases first. + switch (opcode) { + case PIX_CLR: + call aclri (px_dst[ds], npix) + return + case PIX_SET: + call amovki (data, px_dst[ds], npix) + goto out_ + case PIX_SRC: + if (src_maxval != 1) + call amovi (px_src[xs], px_dst[ds], npix) + else { + do i = 1, npix + if (px_src[xs+i-1] > 0) + px_dst[ds+i-1] = src_value + else + px_dst[ds+i-1] = 0 + } + + goto out_ + case PIX_DST: + return # no-op + } + + # Integer or boolean source mask? + if (src_maxval != 1) { + # Integer source mask; operate directly on source mask. + + switch (opcode) { + case PIX_NOTSRC: + do i = 1, npix + px_dst[ds+i-1] = not (px_src[xs+i-1]) + case PIX_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = not (px_dst[xs+i-1]) + + case PIX_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (px_src[xs+i-1], px_dst[ds+i-1]) + case PIX_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (px_src[xs+i-1], px_dst[ds+i-1]) + case PIX_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = xor (px_src[xs+i-1], px_dst[ds+i-1]) + + case PIX_SRC_AND_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = and (px_src[xs+i-1], not(px_dst[ds+i-1])) + case PIX_SRC_OR_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = or (px_src[xs+i-1], not(px_dst[ds+i-1])) + case PIX_NOTSRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (not(px_src[xs+i-1]), px_dst[ds+i-1]) + case PIX_NOTSRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (not(px_src[xs+i-1]), px_dst[ds+i-1]) + + case PIX_NOT_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = not (and (px_src[xs+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = not ( or (px_src[xs+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = not (xor (px_src[xs+i-1], px_dst[ds+i-1])) + } + + } else { + # Boolean source mask; use integer DATA value from ROP if source + # mask pixel is set. + + call smark (sp) + call salloc (src, npix, TY_INT) + + do i = 1, npix + if (px_src[xs+i-1] > 0) + Memi[src+i-1] = src_value + else + Memi[src+i-1] = 0 + + switch (opcode) { + case PIX_NOTSRC: + do i = 1, npix + px_dst[ds+i-1] = not (Memi[src+i-1]) + case PIX_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = not (px_dst[xs+i-1]) + + case PIX_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (Memi[src+i-1], px_dst[ds+i-1]) + case PIX_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (Memi[src+i-1], px_dst[ds+i-1]) + case PIX_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = xor (Memi[src+i-1], px_dst[ds+i-1]) + + case PIX_SRC_AND_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = and (Memi[src+i-1], not(px_dst[ds+i-1])) + case PIX_SRC_OR_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = or (Memi[src+i-1], not(px_dst[ds+i-1])) + case PIX_NOTSRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (not(Memi[src+i-1]), px_dst[ds+i-1]) + case PIX_NOTSRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (not(Memi[src+i-1]), px_dst[ds+i-1]) + + case PIX_NOT_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = not (and (Memi[src+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = not ( or (Memi[src+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = not (xor (Memi[src+i-1], px_dst[ds+i-1])) + } + + call sfree (sp) + } +out_ + # If writing to an integer mask, mask the data to the indicated max + # value (necessary to avoid very large values if any NOT operations + # occurred). If writing to a boolean mask, map positive integer mask + # values to 1. + + if (dst_maxval == 1) { + data = 1 + call argti (px_dst[ds], npix, ceil, data) + } else if (dst_maxval > 1) { + data = dst_maxval + call aandki (px_dst[ds], data, px_dst[ds], npix) + } +end diff --git a/sys/plio/tf/plpropl.x b/sys/plio/tf/plpropl.x new file mode 100644 index 00000000..1aa3b21c --- /dev/null +++ b/sys/plio/tf/plpropl.x @@ -0,0 +1,177 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_PIXROP -- Rasterop between source and destination pixel arrays. + +procedure pl_pixropl (px_src,xs,src_maxval, px_dst,ds,dst_maxval, npix, rop) + +long px_src[ARB] #I source pixel array +int xs #I starting pixel index in src +int src_maxval #I max pixel value in src mask +long px_dst[ARB] #O destination pixel array +int ds #I starting pixel index in dst +int dst_maxval #I max pixel value in dst mask +int npix #I number of pixels to convert +int rop #I rasterop + +pointer sp, src +int opcode, i +long data, ceil, src_value +int and(), or(), xor(), not() +define out_ 91 + +begin + opcode = R_OPCODE(rop) + data = R_DATA(rop) + ceil = 0 + + # Pixel value to be used if input mask is boolean. + if (src_maxval == 1) { + src_value = data + if (src_value <= 0) + src_value = dst_maxval + } + + # Handle the easy cases first. + switch (opcode) { + case PIX_CLR: + call aclrl (px_dst[ds], npix) + return + case PIX_SET: + call amovkl (data, px_dst[ds], npix) + goto out_ + case PIX_SRC: + if (src_maxval != 1) + call amovl (px_src[xs], px_dst[ds], npix) + else { + do i = 1, npix + if (px_src[xs+i-1] > 0) + px_dst[ds+i-1] = src_value + else + px_dst[ds+i-1] = 0 + } + + goto out_ + case PIX_DST: + return # no-op + } + + # Integer or boolean source mask? + if (src_maxval != 1) { + # Integer source mask; operate directly on source mask. + + switch (opcode) { + case PIX_NOTSRC: + do i = 1, npix + px_dst[ds+i-1] = not (px_src[xs+i-1]) + case PIX_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = not (px_dst[xs+i-1]) + + case PIX_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (px_src[xs+i-1], px_dst[ds+i-1]) + case PIX_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (px_src[xs+i-1], px_dst[ds+i-1]) + case PIX_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = xor (px_src[xs+i-1], px_dst[ds+i-1]) + + case PIX_SRC_AND_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = and (px_src[xs+i-1], not(px_dst[ds+i-1])) + case PIX_SRC_OR_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = or (px_src[xs+i-1], not(px_dst[ds+i-1])) + case PIX_NOTSRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (not(px_src[xs+i-1]), px_dst[ds+i-1]) + case PIX_NOTSRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (not(px_src[xs+i-1]), px_dst[ds+i-1]) + + case PIX_NOT_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = not (and (px_src[xs+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = not ( or (px_src[xs+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = not (xor (px_src[xs+i-1], px_dst[ds+i-1])) + } + + } else { + # Boolean source mask; use integer DATA value from ROP if source + # mask pixel is set. + + call smark (sp) + call salloc (src, npix, TY_LONG) + + do i = 1, npix + if (px_src[xs+i-1] > 0) + Meml[src+i-1] = src_value + else + Meml[src+i-1] = 0 + + switch (opcode) { + case PIX_NOTSRC: + do i = 1, npix + px_dst[ds+i-1] = not (Meml[src+i-1]) + case PIX_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = not (px_dst[xs+i-1]) + + case PIX_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (Meml[src+i-1], px_dst[ds+i-1]) + case PIX_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (Meml[src+i-1], px_dst[ds+i-1]) + case PIX_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = xor (Meml[src+i-1], px_dst[ds+i-1]) + + case PIX_SRC_AND_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = and (Meml[src+i-1], not(px_dst[ds+i-1])) + case PIX_SRC_OR_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = or (Meml[src+i-1], not(px_dst[ds+i-1])) + case PIX_NOTSRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (not(Meml[src+i-1]), px_dst[ds+i-1]) + case PIX_NOTSRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (not(Meml[src+i-1]), px_dst[ds+i-1]) + + case PIX_NOT_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = not (and (Meml[src+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = not ( or (Meml[src+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = not (xor (Meml[src+i-1], px_dst[ds+i-1])) + } + + call sfree (sp) + } +out_ + # If writing to an integer mask, mask the data to the indicated max + # value (necessary to avoid very large values if any NOT operations + # occurred). If writing to a boolean mask, map positive integer mask + # values to 1. + + if (dst_maxval == 1) { + data = 1 + call argtl (px_dst[ds], npix, ceil, data) + } else if (dst_maxval > 1) { + data = dst_maxval + call aandkl (px_dst[ds], data, px_dst[ds], npix) + } +end diff --git a/sys/plio/tf/plprops.x b/sys/plio/tf/plprops.x new file mode 100644 index 00000000..f06baadb --- /dev/null +++ b/sys/plio/tf/plprops.x @@ -0,0 +1,177 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_PIXROP -- Rasterop between source and destination pixel arrays. + +procedure pl_pixrops (px_src,xs,src_maxval, px_dst,ds,dst_maxval, npix, rop) + +short px_src[ARB] #I source pixel array +int xs #I starting pixel index in src +int src_maxval #I max pixel value in src mask +short px_dst[ARB] #O destination pixel array +int ds #I starting pixel index in dst +int dst_maxval #I max pixel value in dst mask +int npix #I number of pixels to convert +int rop #I rasterop + +pointer sp, src +int opcode, i +short data, ceil, src_value +int and(), or(), xor(), not() +define out_ 91 + +begin + opcode = R_OPCODE(rop) + data = R_DATA(rop) + ceil = 0 + + # Pixel value to be used if input mask is boolean. + if (src_maxval == 1) { + src_value = data + if (src_value <= 0) + src_value = dst_maxval + } + + # Handle the easy cases first. + switch (opcode) { + case PIX_CLR: + call aclrs (px_dst[ds], npix) + return + case PIX_SET: + call amovks (data, px_dst[ds], npix) + goto out_ + case PIX_SRC: + if (src_maxval != 1) + call amovs (px_src[xs], px_dst[ds], npix) + else { + do i = 1, npix + if (px_src[xs+i-1] > 0) + px_dst[ds+i-1] = src_value + else + px_dst[ds+i-1] = 0 + } + + goto out_ + case PIX_DST: + return # no-op + } + + # Integer or boolean source mask? + if (src_maxval != 1) { + # Integer source mask; operate directly on source mask. + + switch (opcode) { + case PIX_NOTSRC: + do i = 1, npix + px_dst[ds+i-1] = not (px_src[xs+i-1]) + case PIX_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = not (px_dst[xs+i-1]) + + case PIX_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (px_src[xs+i-1], px_dst[ds+i-1]) + case PIX_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (px_src[xs+i-1], px_dst[ds+i-1]) + case PIX_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = xor (px_src[xs+i-1], px_dst[ds+i-1]) + + case PIX_SRC_AND_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = and (px_src[xs+i-1], not(px_dst[ds+i-1])) + case PIX_SRC_OR_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = or (px_src[xs+i-1], not(px_dst[ds+i-1])) + case PIX_NOTSRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (not(px_src[xs+i-1]), px_dst[ds+i-1]) + case PIX_NOTSRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (not(px_src[xs+i-1]), px_dst[ds+i-1]) + + case PIX_NOT_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = not (and (px_src[xs+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = not ( or (px_src[xs+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = not (xor (px_src[xs+i-1], px_dst[ds+i-1])) + } + + } else { + # Boolean source mask; use integer DATA value from ROP if source + # mask pixel is set. + + call smark (sp) + call salloc (src, npix, TY_SHORT) + + do i = 1, npix + if (px_src[xs+i-1] > 0) + Mems[src+i-1] = src_value + else + Mems[src+i-1] = 0 + + switch (opcode) { + case PIX_NOTSRC: + do i = 1, npix + px_dst[ds+i-1] = not (Mems[src+i-1]) + case PIX_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = not (px_dst[xs+i-1]) + + case PIX_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (Mems[src+i-1], px_dst[ds+i-1]) + case PIX_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (Mems[src+i-1], px_dst[ds+i-1]) + case PIX_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = xor (Mems[src+i-1], px_dst[ds+i-1]) + + case PIX_SRC_AND_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = and (Mems[src+i-1], not(px_dst[ds+i-1])) + case PIX_SRC_OR_NOTDST: + do i = 1, npix + px_dst[ds+i-1] = or (Mems[src+i-1], not(px_dst[ds+i-1])) + case PIX_NOTSRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = and (not(Mems[src+i-1]), px_dst[ds+i-1]) + case PIX_NOTSRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = or (not(Mems[src+i-1]), px_dst[ds+i-1]) + + case PIX_NOT_SRC_AND_DST: + do i = 1, npix + px_dst[ds+i-1] = not (and (Mems[src+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_OR_DST: + do i = 1, npix + px_dst[ds+i-1] = not ( or (Mems[src+i-1], px_dst[ds+i-1])) + case PIX_NOT_SRC_XOR_DST: + do i = 1, npix + px_dst[ds+i-1] = not (xor (Mems[src+i-1], px_dst[ds+i-1])) + } + + call sfree (sp) + } +out_ + # If writing to an integer mask, mask the data to the indicated max + # value (necessary to avoid very large values if any NOT operations + # occurred). If writing to a boolean mask, map positive integer mask + # values to 1. + + if (dst_maxval == 1) { + data = 1 + call argts (px_dst[ds], npix, ceil, data) + } else if (dst_maxval > 1) { + data = dst_maxval + call aandks (px_dst[ds], data, px_dst[ds], npix) + } +end diff --git a/sys/plio/tf/plr2li.x b/sys/plio/tf/plr2li.x new file mode 100644 index 00000000..f6fb6c79 --- /dev/null +++ b/sys/plio/tf/plr2li.x @@ -0,0 +1,130 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_R2L -- Convert a range list to a line list. The length of the output +# line list is returned as the function value. + +int procedure pl_r2li (rl_src, xs, ll_dst, npix) + +int rl_src[3,ARB] #I input range list +int xs #I starting pixel index in range list +short ll_dst[ARB] #O destination line list +int npix #I number of pixels to convert + +int hi, pv +int last, xe, x1, x2, iz, op, np, nz, nr, dv, v, i +define done_ 91 + +begin + # No input pixels? + nr = RL_LEN(rl_src) + if (npix <= 0 || nr <= 0) + return (0) + + # Initialize the linelist header. + LL_VERSION(ll_dst) = LL_CURVERSION + LL_HDRLEN(ll_dst) = LL_CURHDRLEN + LL_NREFS(ll_dst) = 0 + LL_SETBLEN(ll_dst,0) + + xe = xs + npix - 1 + op = LL_CURHDRLEN + 1 + iz = xs + hi = 1 + + # Process the array of range lists. + do i = RL_FIRST, nr + 1 { + if (i <= nr) { + # Load next range. + x1 = rl_src[1,i] + np = rl_src[2,i] + pv = rl_src[3,i] + x2 = x1 + np - 1 + last = x2 + + # Get an inbounds range. + if (x1 > xe) + break + else if (xs > x2) + next + else if (x1 < xs) + x1 = xs + else if (x2 > xe) + x2 = xe + + # Go again if nothing inbounds. + nz = x1 - iz + np = x2 - x1 + 1 + if (np <= 0) + next + + } else if (iz < xe) { + # At end of input range list, but need to output a ZN. + nz = xe - iz + 1 + np = 0 + pv = 0 + } else + break + + # Encode an instruction to regenerate the current range I0-IP + # of N data values of nonzero level PV. In the most complex case + # we must update the high value and output a range of zeros, + # followed by a range of NP high values. If NP is 1, we can + # probably use a PN or [ID]S instruction to save space. + + # Change the high value? + if (pv > 0) { + dv = pv - hi + if (dv != 0) { + # Output IH or DH instruction? + hi = pv + if (abs(dv) > I_DATAMAX) { + ll_dst[op] = M_SH + and (int(pv), I_DATAMAX) + op = op + 1 + ll_dst[op] = pv / I_SHIFT + op = op + 1 + } else { + if (dv < 0) + ll_dst[op] = M_DH + (-dv) + else + ll_dst[op] = M_IH + dv + op = op + 1 + + # Convert to IS or DS if range is a single pixel. + if (np == 1 && nz == 0) { + v = ll_dst[op-1] + ll_dst[op-1] = or (v, M_MOVE) + goto done_ + } + } + } + } + + # Output range of zeros to catch up to current range? + if (nz > 0) { + # Output the ZN instruction. + for (; nz > 0; nz = nz - (I_DATAMAX-1)) { + ll_dst[op] = M_ZN + min(I_DATAMAX-1,nz) + op = op + 1 + } + # Convert to PN if range is a single pixel. + if (np == 1 && pv > 0 && x2 == last) { + ll_dst[op-1] = ll_dst[op-1] + M_PN + 1 + goto done_ + } + } + + # The only thing left is the HN instruction if we get here. + for (; np > 0; np = np - I_DATAMAX) { + ll_dst[op] = M_HN + min(I_DATAMAX,np) + op = op + 1 + } +done_ + iz = x2 + 1 + } + + LL_SETLEN(ll_dst, op - 1) + return (op - 1) +end diff --git a/sys/plio/tf/plr2ll.x b/sys/plio/tf/plr2ll.x new file mode 100644 index 00000000..b21d6678 --- /dev/null +++ b/sys/plio/tf/plr2ll.x @@ -0,0 +1,130 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_R2L -- Convert a range list to a line list. The length of the output +# line list is returned as the function value. + +int procedure pl_r2ll (rl_src, xs, ll_dst, npix) + +long rl_src[3,ARB] #I input range list +int xs #I starting pixel index in range list +short ll_dst[ARB] #O destination line list +int npix #I number of pixels to convert + +long hi, pv +int last, xe, x1, x2, iz, op, np, nz, nr, dv, v, i +define done_ 91 + +begin + # No input pixels? + nr = RL_LEN(rl_src) + if (npix <= 0 || nr <= 0) + return (0) + + # Initialize the linelist header. + LL_VERSION(ll_dst) = LL_CURVERSION + LL_HDRLEN(ll_dst) = LL_CURHDRLEN + LL_NREFS(ll_dst) = 0 + LL_SETBLEN(ll_dst,0) + + xe = xs + npix - 1 + op = LL_CURHDRLEN + 1 + iz = xs + hi = 1 + + # Process the array of range lists. + do i = RL_FIRST, nr + 1 { + if (i <= nr) { + # Load next range. + x1 = rl_src[1,i] + np = rl_src[2,i] + pv = rl_src[3,i] + x2 = x1 + np - 1 + last = x2 + + # Get an inbounds range. + if (x1 > xe) + break + else if (xs > x2) + next + else if (x1 < xs) + x1 = xs + else if (x2 > xe) + x2 = xe + + # Go again if nothing inbounds. + nz = x1 - iz + np = x2 - x1 + 1 + if (np <= 0) + next + + } else if (iz < xe) { + # At end of input range list, but need to output a ZN. + nz = xe - iz + 1 + np = 0 + pv = 0 + } else + break + + # Encode an instruction to regenerate the current range I0-IP + # of N data values of nonzero level PV. In the most complex case + # we must update the high value and output a range of zeros, + # followed by a range of NP high values. If NP is 1, we can + # probably use a PN or [ID]S instruction to save space. + + # Change the high value? + if (pv > 0) { + dv = pv - hi + if (dv != 0) { + # Output IH or DH instruction? + hi = pv + if (abs(dv) > I_DATAMAX) { + ll_dst[op] = M_SH + and (int(pv), I_DATAMAX) + op = op + 1 + ll_dst[op] = pv / I_SHIFT + op = op + 1 + } else { + if (dv < 0) + ll_dst[op] = M_DH + (-dv) + else + ll_dst[op] = M_IH + dv + op = op + 1 + + # Convert to IS or DS if range is a single pixel. + if (np == 1 && nz == 0) { + v = ll_dst[op-1] + ll_dst[op-1] = or (v, M_MOVE) + goto done_ + } + } + } + } + + # Output range of zeros to catch up to current range? + if (nz > 0) { + # Output the ZN instruction. + for (; nz > 0; nz = nz - (I_DATAMAX-1)) { + ll_dst[op] = M_ZN + min(I_DATAMAX-1,nz) + op = op + 1 + } + # Convert to PN if range is a single pixel. + if (np == 1 && pv > 0 && x2 == last) { + ll_dst[op-1] = ll_dst[op-1] + M_PN + 1 + goto done_ + } + } + + # The only thing left is the HN instruction if we get here. + for (; np > 0; np = np - I_DATAMAX) { + ll_dst[op] = M_HN + min(I_DATAMAX,np) + op = op + 1 + } +done_ + iz = x2 + 1 + } + + LL_SETLEN(ll_dst, op - 1) + return (op - 1) +end diff --git a/sys/plio/tf/plr2ls.x b/sys/plio/tf/plr2ls.x new file mode 100644 index 00000000..6aceca17 --- /dev/null +++ b/sys/plio/tf/plr2ls.x @@ -0,0 +1,130 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_R2L -- Convert a range list to a line list. The length of the output +# line list is returned as the function value. + +int procedure pl_r2ls (rl_src, xs, ll_dst, npix) + +short rl_src[3,ARB] #I input range list +int xs #I starting pixel index in range list +short ll_dst[ARB] #O destination line list +int npix #I number of pixels to convert + +short hi, pv +int last, xe, x1, x2, iz, op, np, nz, nr, dv, v, i +define done_ 91 + +begin + # No input pixels? + nr = RL_LEN(rl_src) + if (npix <= 0 || nr <= 0) + return (0) + + # Initialize the linelist header. + LL_VERSION(ll_dst) = LL_CURVERSION + LL_HDRLEN(ll_dst) = LL_CURHDRLEN + LL_NREFS(ll_dst) = 0 + LL_SETBLEN(ll_dst,0) + + xe = xs + npix - 1 + op = LL_CURHDRLEN + 1 + iz = xs + hi = 1 + + # Process the array of range lists. + do i = RL_FIRST, nr + 1 { + if (i <= nr) { + # Load next range. + x1 = rl_src[1,i] + np = rl_src[2,i] + pv = rl_src[3,i] + x2 = x1 + np - 1 + last = x2 + + # Get an inbounds range. + if (x1 > xe) + break + else if (xs > x2) + next + else if (x1 < xs) + x1 = xs + else if (x2 > xe) + x2 = xe + + # Go again if nothing inbounds. + nz = x1 - iz + np = x2 - x1 + 1 + if (np <= 0) + next + + } else if (iz < xe) { + # At end of input range list, but need to output a ZN. + nz = xe - iz + 1 + np = 0 + pv = 0 + } else + break + + # Encode an instruction to regenerate the current range I0-IP + # of N data values of nonzero level PV. In the most complex case + # we must update the high value and output a range of zeros, + # followed by a range of NP high values. If NP is 1, we can + # probably use a PN or [ID]S instruction to save space. + + # Change the high value? + if (pv > 0) { + dv = pv - hi + if (dv != 0) { + # Output IH or DH instruction? + hi = pv + if (abs(dv) > I_DATAMAX) { + ll_dst[op] = M_SH + and (int(pv), I_DATAMAX) + op = op + 1 + ll_dst[op] = pv / I_SHIFT + op = op + 1 + } else { + if (dv < 0) + ll_dst[op] = M_DH + (-dv) + else + ll_dst[op] = M_IH + dv + op = op + 1 + + # Convert to IS or DS if range is a single pixel. + if (np == 1 && nz == 0) { + v = ll_dst[op-1] + ll_dst[op-1] = or (v, M_MOVE) + goto done_ + } + } + } + } + + # Output range of zeros to catch up to current range? + if (nz > 0) { + # Output the ZN instruction. + for (; nz > 0; nz = nz - (I_DATAMAX-1)) { + ll_dst[op] = M_ZN + min(I_DATAMAX-1,nz) + op = op + 1 + } + # Convert to PN if range is a single pixel. + if (np == 1 && pv > 0 && x2 == last) { + ll_dst[op-1] = ll_dst[op-1] + M_PN + 1 + goto done_ + } + } + + # The only thing left is the HN instruction if we get here. + for (; np > 0; np = np - I_DATAMAX) { + ll_dst[op] = M_HN + min(I_DATAMAX,np) + op = op + 1 + } +done_ + iz = x2 + 1 + } + + LL_SETLEN(ll_dst, op - 1) + return (op - 1) +end diff --git a/sys/plio/tf/plr2pi.x b/sys/plio/tf/plr2pi.x new file mode 100644 index 00000000..57db5b63 --- /dev/null +++ b/sys/plio/tf/plr2pi.x @@ -0,0 +1,74 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_R2P -- Convert a range list to a pixel array. The number of pixels +# output (always npix) is returned as the function value. + +int procedure pl_r2pi (rl_src, xs, px_dst, npix) + +int rl_src[3,ARB] #I input range list +int xs #I starting pixel index in range list +int px_dst[ARB] #O output pixel array +int npix #I number of pixels to convert + +int hi, pv +int xe, x1, x2, iz, op, np, nz, nr, i, j +define done_ 91 + +begin + # No input pixels? + nr = RL_LEN(rl_src) + if (npix <= 0 || nr <= 0) + return (0) + + xe = xs + npix - 1 + iz = xs + op = 1 + hi = 1 + + # Process the array of range lists. + do i = RL_FIRST, nr { + x1 = rl_src[1,i] + np = rl_src[2,i] + pv = rl_src[3,i] + x2 = x1 + np - 1 + + # Get an inbounds range. + if (x1 > xe) + break + else if (xs > x2) + next + else if (x1 < xs) + x1 = xs + else if (x2 > xe) + x2 = xe + + nz = x1 - iz + np = x2 - x1 + 1 + if (np <= 0) + next + + # Output range of zeros to catch up to current range? + if (nz > 0) { + do j = 1, nz + px_dst[op+j-1] = 0 + op = op + nz + } + + # Output the pixels. + do j = 1, np + px_dst[op+j-1] = pv + op = op + np +done_ + x1 = x2 + 1 + iz = x1 + } + + # Zero any remaining output range. + do i = op, npix + px_dst[i] = 0 + + return (npix) +end diff --git a/sys/plio/tf/plr2pl.x b/sys/plio/tf/plr2pl.x new file mode 100644 index 00000000..763bb8d2 --- /dev/null +++ b/sys/plio/tf/plr2pl.x @@ -0,0 +1,74 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_R2P -- Convert a range list to a pixel array. The number of pixels +# output (always npix) is returned as the function value. + +int procedure pl_r2pl (rl_src, xs, px_dst, npix) + +long rl_src[3,ARB] #I input range list +int xs #I starting pixel index in range list +long px_dst[ARB] #O output pixel array +int npix #I number of pixels to convert + +long hi, pv +int xe, x1, x2, iz, op, np, nz, nr, i, j +define done_ 91 + +begin + # No input pixels? + nr = RL_LEN(rl_src) + if (npix <= 0 || nr <= 0) + return (0) + + xe = xs + npix - 1 + iz = xs + op = 1 + hi = 1 + + # Process the array of range lists. + do i = RL_FIRST, nr { + x1 = rl_src[1,i] + np = rl_src[2,i] + pv = rl_src[3,i] + x2 = x1 + np - 1 + + # Get an inbounds range. + if (x1 > xe) + break + else if (xs > x2) + next + else if (x1 < xs) + x1 = xs + else if (x2 > xe) + x2 = xe + + nz = x1 - iz + np = x2 - x1 + 1 + if (np <= 0) + next + + # Output range of zeros to catch up to current range? + if (nz > 0) { + do j = 1, nz + px_dst[op+j-1] = 0 + op = op + nz + } + + # Output the pixels. + do j = 1, np + px_dst[op+j-1] = pv + op = op + np +done_ + x1 = x2 + 1 + iz = x1 + } + + # Zero any remaining output range. + do i = op, npix + px_dst[i] = 0 + + return (npix) +end diff --git a/sys/plio/tf/plr2ps.x b/sys/plio/tf/plr2ps.x new file mode 100644 index 00000000..ecba387d --- /dev/null +++ b/sys/plio/tf/plr2ps.x @@ -0,0 +1,74 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PL_R2P -- Convert a range list to a pixel array. The number of pixels +# output (always npix) is returned as the function value. + +int procedure pl_r2ps (rl_src, xs, px_dst, npix) + +short rl_src[3,ARB] #I input range list +int xs #I starting pixel index in range list +short px_dst[ARB] #O output pixel array +int npix #I number of pixels to convert + +short hi, pv +int xe, x1, x2, iz, op, np, nz, nr, i, j +define done_ 91 + +begin + # No input pixels? + nr = RL_LEN(rl_src) + if (npix <= 0 || nr <= 0) + return (0) + + xe = xs + npix - 1 + iz = xs + op = 1 + hi = 1 + + # Process the array of range lists. + do i = RL_FIRST, nr { + x1 = rl_src[1,i] + np = rl_src[2,i] + pv = rl_src[3,i] + x2 = x1 + np - 1 + + # Get an inbounds range. + if (x1 > xe) + break + else if (xs > x2) + next + else if (x1 < xs) + x1 = xs + else if (x2 > xe) + x2 = xe + + nz = x1 - iz + np = x2 - x1 + 1 + if (np <= 0) + next + + # Output range of zeros to catch up to current range? + if (nz > 0) { + do j = 1, nz + px_dst[op+j-1] = 0 + op = op + nz + } + + # Output the pixels. + do j = 1, np + px_dst[op+j-1] = pv + op = op + np +done_ + x1 = x2 + 1 + iz = x1 + } + + # Zero any remaining output range. + do i = op, npix + px_dst[i] = 0 + + return (npix) +end diff --git a/sys/plio/tf/plreqi.x b/sys/plio/tf/plreqi.x new file mode 100644 index 00000000..0307efea --- /dev/null +++ b/sys/plio/tf/plreqi.x @@ -0,0 +1,27 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> + +# PLR_EQUAL -- Compare two range lists for equality. + +bool procedure plr_equali (r1, r2) + +int r1[3,ARB] #I range list 1 +int r2[3,ARB] #I range list 2 + +int i +int len1, len2 + +begin + len1 = RL_LEN(r1) + len2 = RL_LEN(r2) + + if (len1 != len2) + return (false) + + do i = RL_FIRST, len1 + if (r1[1,i] != r2[1,i] || r1[2,i] != r2[2,i] || r1[3,i] != r2[3,i]) + return (false) + + return (true) +end diff --git a/sys/plio/tf/plreql.x b/sys/plio/tf/plreql.x new file mode 100644 index 00000000..1fb76d6a --- /dev/null +++ b/sys/plio/tf/plreql.x @@ -0,0 +1,27 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> + +# PLR_EQUAL -- Compare two range lists for equality. + +bool procedure plr_equall (r1, r2) + +long r1[3,ARB] #I range list 1 +long r2[3,ARB] #I range list 2 + +int i +int len1, len2 + +begin + len1 = RL_LEN(r1) + len2 = RL_LEN(r2) + + if (len1 != len2) + return (false) + + do i = RL_FIRST, len1 + if (r1[1,i] != r2[1,i] || r1[2,i] != r2[2,i] || r1[3,i] != r2[3,i]) + return (false) + + return (true) +end diff --git a/sys/plio/tf/plreqs.x b/sys/plio/tf/plreqs.x new file mode 100644 index 00000000..b44bf4da --- /dev/null +++ b/sys/plio/tf/plreqs.x @@ -0,0 +1,27 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> + +# PLR_EQUAL -- Compare two range lists for equality. + +bool procedure plr_equals (r1, r2) + +short r1[3,ARB] #I range list 1 +short r2[3,ARB] #I range list 2 + +int i +int len1, len2 + +begin + len1 = RL_LEN(r1) + len2 = RL_LEN(r2) + + if (len1 != len2) + return (false) + + do i = RL_FIRST, len1 + if (r1[1,i] != r2[1,i] || r1[2,i] != r2[2,i] || r1[3,i] != r2[3,i]) + return (false) + + return (true) +end diff --git a/sys/plio/tf/plrpri.x b/sys/plio/tf/plrpri.x new file mode 100644 index 00000000..a74e7791 --- /dev/null +++ b/sys/plio/tf/plrpri.x @@ -0,0 +1,56 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PLR_PRINT -- Print a range list on the given output stream. + +procedure plr_printi (rl, fd, label, firstcol, maxcol) + +int rl[3,ARB] #I range list +int fd #I output file +char label[ARB] #I line label +int firstcol #I first column for output +int maxcol #I width of formatted output + +pointer sp, buf +int col, rn, r_len, x, n, pv +int strlen() + +begin + call smark (sp) + call salloc (buf, SZ_LINE, TY_CHAR) + + # Output the line label and advance to the first column. If the label + # extends beyond the first column, start a new line. + + call putline (fd, label) + col = strlen (label) + 1 + if (col > firstcol) + call pl_debugout (fd, "", col, firstcol, maxcol) + + r_len = RL_LEN(rl) + + # Decode the range list proper. + do rn = RL_FIRST, r_len { + x = RL_X(rl,rn) + n = RL_N(rl,rn) + pv = RL_V(rl,rn) + + if (n == 1) { + call sprintf (Memc[buf], SZ_LINE, "%d(%d)") + call pargi (x) + call pargi (pv) + } else { + call sprintf (Memc[buf], SZ_LINE, "%d-%d(%d)") + call pargi (x) + call pargi (x+n-1) + call pargi (pv) + } + + call pl_debugout (fd, Memc[buf], col, firstcol, maxcol) + } + + call pl_debugout (fd, "", col, firstcol, maxcol) + call sfree (sp) +end diff --git a/sys/plio/tf/plrprl.x b/sys/plio/tf/plrprl.x new file mode 100644 index 00000000..6357cd71 --- /dev/null +++ b/sys/plio/tf/plrprl.x @@ -0,0 +1,56 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PLR_PRINT -- Print a range list on the given output stream. + +procedure plr_printl (rl, fd, label, firstcol, maxcol) + +long rl[3,ARB] #I range list +int fd #I output file +char label[ARB] #I line label +int firstcol #I first column for output +int maxcol #I width of formatted output + +pointer sp, buf +int col, rn, r_len, x, n, pv +int strlen() + +begin + call smark (sp) + call salloc (buf, SZ_LINE, TY_CHAR) + + # Output the line label and advance to the first column. If the label + # extends beyond the first column, start a new line. + + call putline (fd, label) + col = strlen (label) + 1 + if (col > firstcol) + call pl_debugout (fd, "", col, firstcol, maxcol) + + r_len = RL_LEN(rl) + + # Decode the range list proper. + do rn = RL_FIRST, r_len { + x = RL_X(rl,rn) + n = RL_N(rl,rn) + pv = RL_V(rl,rn) + + if (n == 1) { + call sprintf (Memc[buf], SZ_LINE, "%d(%d)") + call pargi (x) + call pargi (pv) + } else { + call sprintf (Memc[buf], SZ_LINE, "%d-%d(%d)") + call pargi (x) + call pargi (x+n-1) + call pargi (pv) + } + + call pl_debugout (fd, Memc[buf], col, firstcol, maxcol) + } + + call pl_debugout (fd, "", col, firstcol, maxcol) + call sfree (sp) +end diff --git a/sys/plio/tf/plrprs.x b/sys/plio/tf/plrprs.x new file mode 100644 index 00000000..e055f851 --- /dev/null +++ b/sys/plio/tf/plrprs.x @@ -0,0 +1,56 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> + +# PLR_PRINT -- Print a range list on the given output stream. + +procedure plr_prints (rl, fd, label, firstcol, maxcol) + +short rl[3,ARB] #I range list +int fd #I output file +char label[ARB] #I line label +int firstcol #I first column for output +int maxcol #I width of formatted output + +pointer sp, buf +int col, rn, r_len, x, n, pv +int strlen() + +begin + call smark (sp) + call salloc (buf, SZ_LINE, TY_CHAR) + + # Output the line label and advance to the first column. If the label + # extends beyond the first column, start a new line. + + call putline (fd, label) + col = strlen (label) + 1 + if (col > firstcol) + call pl_debugout (fd, "", col, firstcol, maxcol) + + r_len = RL_LEN(rl) + + # Decode the range list proper. + do rn = RL_FIRST, r_len { + x = RL_X(rl,rn) + n = RL_N(rl,rn) + pv = RL_V(rl,rn) + + if (n == 1) { + call sprintf (Memc[buf], SZ_LINE, "%d(%d)") + call pargi (x) + call pargi (pv) + } else { + call sprintf (Memc[buf], SZ_LINE, "%d-%d(%d)") + call pargi (x) + call pargi (x+n-1) + call pargi (pv) + } + + call pl_debugout (fd, Memc[buf], col, firstcol, maxcol) + } + + call pl_debugout (fd, "", col, firstcol, maxcol) + call sfree (sp) +end diff --git a/sys/plio/tf/plrropi.x b/sys/plio/tf/plrropi.x new file mode 100644 index 00000000..72292323 --- /dev/null +++ b/sys/plio/tf/plrropi.x @@ -0,0 +1,195 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> +include "../plrseg.h" + +# PL_RANGEROP -- Rasterop operation between source and destination range lists. +# The indicated rasterop operation is performed upon the source and destination +# range lists, writing the result to RL_OUT, which is a copy of RL_DST except +# for the region affected by the rasterop operation (note that the destination +# range list cannot be edited in place since it may change size). + +procedure pl_rangeropi (rl_src, xs, src_maxval, + rl_dst, ds, dst_maxval, rl_out, npix, rop) + +int rl_src[3,ARB] #I source range list +int xs #I starting pixel index in src range list +int src_maxval #I max pixel value in src mask +int rl_dst[3,ARB] #I destination range list +int ds #I starting pixel index in dst range list +int dst_maxval #I max pixel value in dst mask +int rl_out[3,ARB] #O output list (edited version of rl_dst) +int npix #I number of pixels to convert +int rop #I rasterop + +bool need_src, need_dst, rop_enable +int data, src_value, v_src, v_dst, pv +int segsize, opcode, x, i, np, rn_o, p +int d_src[LEN_PLRDES], d_dst[LEN_PLRDES] + +begin + need_src = R_NEED_SRC(rop) + need_dst = R_NEED_DST(rop) + opcode = R_OPCODE(rop) + data = R_DATA(rop) + + # Pixel value to be used if input mask is boolean. + if (src_maxval == 1) { + src_value = data + if (src_value <= 0) + src_value = dst_maxval + } + + # Advance to the desired position in the source list, discarding + # the unused ranges. The point XS may lie within a range or in a + # zero area of the input line. + + if (need_src) { + x = 1 + plr_init (rl_src, d_src) + do i = 1, ARB { + np = min (plr_nleft(d_src), xs - x) + plr_getseg (rl_src, d_src, np, v_src) + x = x + np + if (x >= xs || np == 0) + break + } + } + + # Advance through both the source and destination lists, extracting + # line segments which have a constant value in each input list; the + # values for the two lists may differ. Apply the given rasterop to + # the source and destination pixel values and write each line segment + # as a range to the output list. If the ranges in the two input lists + # differ (randomly overlap) then the output list will generally be + # more fragmented, i.e., have more ranges of constant value. As each + # output range is generated compare it with the previous range to see + # if they can be joined, as applying a rasterop may cause two different + # ranges to have the same value. + + x = 1 + rn_o = RL_FIRST + segsize = ds - 1 + rop_enable = false + plr_init (rl_dst, d_dst) + + do i = 1, ARB { + # Set up for the next segment (before, in, and after the region to + # which the ROP applies), when the current segment is exhausted. + + if (segsize <= 0) + if (!rop_enable) { + # Begin processing central region. + segsize = npix + rop_enable = true + if (segsize <= 0) + next + } else { + # Begin processing final region. + segsize = ARB + rop_enable = false + } + + # Determine the length of the next output segment. This is the + # largest segment of constant value formed by the intersection of + # the two lists. If bounds checking has been properly performed + # then it should not be possible to see nleft=zero on either input + # list. Note that zeroed regions are valid data here. + + np = min (segsize, plr_nleft(d_dst)) + if (need_src && rop_enable && plr_nleft(d_src) > 0) + np = min (np, plr_nleft(d_src)) + if (np <= 0) + break + + # Get the segment value and advance the line pointers. We must + # read the DST list whether or not we will use the data, since + # the list pointer must be advanced NPIX pixels so that we may + # copy the remainder of the list after the loop. + + plr_getseg (rl_dst, d_dst, np, v_dst) + if (rop_enable) { + # Get v_src. + if (need_src) { + v_src = 0 + if (plr_nleft (d_src) > 0) + plr_getseg (rl_src, d_src, np, v_src) + + if (R_NOTSRC(rop)) { + v_src = not (v_src) + if (src_maxval != 0) + v_src = and (int(v_src), src_maxval) + } + + if (v_src != 0 && src_maxval == 1) + v_src = src_value + } + + # Get v_dst. + if (need_dst) { + if (R_NOTDST(rop)) { + v_dst = not (v_dst) + if (dst_maxval != 0) + v_dst = and (int(v_dst), dst_maxval) + } + } + + # Apply the rasterop. + switch (opcode) { + case PIX_CLR: + pv = 0 + case PIX_SET: + pv = data + case PIX_SRC, PIX_NOTSRC: + pv = v_src + case PIX_DST, PIX_NOTDST: + pv = v_dst + case PIX_SRC_AND_DST, PIX_SRC_AND_NOTDST, PIX_NOTSRC_AND_DST: + pv = and (v_src, v_dst) + case PIX_SRC_OR_DST, PIX_SRC_OR_NOTDST, PIX_NOTSRC_OR_DST: + pv = or (v_src, v_dst) + case PIX_SRC_XOR_DST: + pv = xor (v_src, v_dst) + case PIX_NOT_SRC_AND_DST: + pv = not (and (v_src, v_dst)) + case PIX_NOT_SRC_OR_DST: + pv = not (or (v_src, v_dst)) + case PIX_NOT_SRC_XOR_DST: + pv = not (xor (v_src, v_dst)) + } + + # Mask the high bits to prevent negative values, or map int + # to bool for the case of a boolean output mask. + + if (dst_maxval == 1 && pv != 0) + pv = 1 + else if (dst_maxval > 1) + pv = and (int(pv), dst_maxval) + + } else + pv = v_dst + + # Output a nonzero range. + if (pv > 0) { + p = rn_o - 1 + if (p >= RL_FIRST && + pv == rl_out[3,p] && x == rl_out[1,p] + rl_out[2,p]) { + # Merge new range with previous one. + rl_out[2,p] = rl_out[2,p] + np + } else { + rl_out[1,rn_o] = x + rl_out[2,rn_o] = np + rl_out[3,rn_o] = pv + rn_o = rn_o + 1 + } + } + + x = x + np + segsize = segsize - np + } + + # Update the range list header. + call amovi (rl_dst, rl_out, (RL_FIRST - 1) * 3) + RL_LEN(rl_out) = rn_o - 1 +end diff --git a/sys/plio/tf/plrropl.x b/sys/plio/tf/plrropl.x new file mode 100644 index 00000000..ec936e09 --- /dev/null +++ b/sys/plio/tf/plrropl.x @@ -0,0 +1,195 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> +include "../plrseg.h" + +# PL_RANGEROP -- Rasterop operation between source and destination range lists. +# The indicated rasterop operation is performed upon the source and destination +# range lists, writing the result to RL_OUT, which is a copy of RL_DST except +# for the region affected by the rasterop operation (note that the destination +# range list cannot be edited in place since it may change size). + +procedure pl_rangeropl (rl_src, xs, src_maxval, + rl_dst, ds, dst_maxval, rl_out, npix, rop) + +long rl_src[3,ARB] #I source range list +int xs #I starting pixel index in src range list +int src_maxval #I max pixel value in src mask +long rl_dst[3,ARB] #I destination range list +int ds #I starting pixel index in dst range list +int dst_maxval #I max pixel value in dst mask +long rl_out[3,ARB] #O output list (edited version of rl_dst) +int npix #I number of pixels to convert +int rop #I rasterop + +bool need_src, need_dst, rop_enable +long data, src_value, v_src, v_dst, pv +int segsize, opcode, x, i, np, rn_o, p +int d_src[LEN_PLRDES], d_dst[LEN_PLRDES] + +begin + need_src = R_NEED_SRC(rop) + need_dst = R_NEED_DST(rop) + opcode = R_OPCODE(rop) + data = R_DATA(rop) + + # Pixel value to be used if input mask is boolean. + if (src_maxval == 1) { + src_value = data + if (src_value <= 0) + src_value = dst_maxval + } + + # Advance to the desired position in the source list, discarding + # the unused ranges. The point XS may lie within a range or in a + # zero area of the input line. + + if (need_src) { + x = 1 + plr_init (rl_src, d_src) + do i = 1, ARB { + np = min (plr_nleft(d_src), xs - x) + plr_getseg (rl_src, d_src, np, v_src) + x = x + np + if (x >= xs || np == 0) + break + } + } + + # Advance through both the source and destination lists, extracting + # line segments which have a constant value in each input list; the + # values for the two lists may differ. Apply the given rasterop to + # the source and destination pixel values and write each line segment + # as a range to the output list. If the ranges in the two input lists + # differ (randomly overlap) then the output list will generally be + # more fragmented, i.e., have more ranges of constant value. As each + # output range is generated compare it with the previous range to see + # if they can be joined, as applying a rasterop may cause two different + # ranges to have the same value. + + x = 1 + rn_o = RL_FIRST + segsize = ds - 1 + rop_enable = false + plr_init (rl_dst, d_dst) + + do i = 1, ARB { + # Set up for the next segment (before, in, and after the region to + # which the ROP applies), when the current segment is exhausted. + + if (segsize <= 0) + if (!rop_enable) { + # Begin processing central region. + segsize = npix + rop_enable = true + if (segsize <= 0) + next + } else { + # Begin processing final region. + segsize = ARB + rop_enable = false + } + + # Determine the length of the next output segment. This is the + # largest segment of constant value formed by the intersection of + # the two lists. If bounds checking has been properly performed + # then it should not be possible to see nleft=zero on either input + # list. Note that zeroed regions are valid data here. + + np = min (segsize, plr_nleft(d_dst)) + if (need_src && rop_enable && plr_nleft(d_src) > 0) + np = min (np, plr_nleft(d_src)) + if (np <= 0) + break + + # Get the segment value and advance the line pointers. We must + # read the DST list whether or not we will use the data, since + # the list pointer must be advanced NPIX pixels so that we may + # copy the remainder of the list after the loop. + + plr_getseg (rl_dst, d_dst, np, v_dst) + if (rop_enable) { + # Get v_src. + if (need_src) { + v_src = 0 + if (plr_nleft (d_src) > 0) + plr_getseg (rl_src, d_src, np, v_src) + + if (R_NOTSRC(rop)) { + v_src = not (v_src) + if (src_maxval != 0) + v_src = and (int(v_src), src_maxval) + } + + if (v_src != 0 && src_maxval == 1) + v_src = src_value + } + + # Get v_dst. + if (need_dst) { + if (R_NOTDST(rop)) { + v_dst = not (v_dst) + if (dst_maxval != 0) + v_dst = and (int(v_dst), dst_maxval) + } + } + + # Apply the rasterop. + switch (opcode) { + case PIX_CLR: + pv = 0 + case PIX_SET: + pv = data + case PIX_SRC, PIX_NOTSRC: + pv = v_src + case PIX_DST, PIX_NOTDST: + pv = v_dst + case PIX_SRC_AND_DST, PIX_SRC_AND_NOTDST, PIX_NOTSRC_AND_DST: + pv = and (v_src, v_dst) + case PIX_SRC_OR_DST, PIX_SRC_OR_NOTDST, PIX_NOTSRC_OR_DST: + pv = or (v_src, v_dst) + case PIX_SRC_XOR_DST: + pv = xor (v_src, v_dst) + case PIX_NOT_SRC_AND_DST: + pv = not (and (v_src, v_dst)) + case PIX_NOT_SRC_OR_DST: + pv = not (or (v_src, v_dst)) + case PIX_NOT_SRC_XOR_DST: + pv = not (xor (v_src, v_dst)) + } + + # Mask the high bits to prevent negative values, or map int + # to bool for the case of a boolean output mask. + + if (dst_maxval == 1 && pv != 0) + pv = 1 + else if (dst_maxval > 1) + pv = and (int(pv), dst_maxval) + + } else + pv = v_dst + + # Output a nonzero range. + if (pv > 0) { + p = rn_o - 1 + if (p >= RL_FIRST && + pv == rl_out[3,p] && x == rl_out[1,p] + rl_out[2,p]) { + # Merge new range with previous one. + rl_out[2,p] = rl_out[2,p] + np + } else { + rl_out[1,rn_o] = x + rl_out[2,rn_o] = np + rl_out[3,rn_o] = pv + rn_o = rn_o + 1 + } + } + + x = x + np + segsize = segsize - np + } + + # Update the range list header. + call amovl (rl_dst, rl_out, (RL_FIRST - 1) * 3) + RL_LEN(rl_out) = rn_o - 1 +end diff --git a/sys/plio/tf/plrrops.x b/sys/plio/tf/plrrops.x new file mode 100644 index 00000000..b2d9781c --- /dev/null +++ b/sys/plio/tf/plrrops.x @@ -0,0 +1,195 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plset.h> +include <plio.h> +include "../plrseg.h" + +# PL_RANGEROP -- Rasterop operation between source and destination range lists. +# The indicated rasterop operation is performed upon the source and destination +# range lists, writing the result to RL_OUT, which is a copy of RL_DST except +# for the region affected by the rasterop operation (note that the destination +# range list cannot be edited in place since it may change size). + +procedure pl_rangerops (rl_src, xs, src_maxval, + rl_dst, ds, dst_maxval, rl_out, npix, rop) + +short rl_src[3,ARB] #I source range list +int xs #I starting pixel index in src range list +int src_maxval #I max pixel value in src mask +short rl_dst[3,ARB] #I destination range list +int ds #I starting pixel index in dst range list +int dst_maxval #I max pixel value in dst mask +short rl_out[3,ARB] #O output list (edited version of rl_dst) +int npix #I number of pixels to convert +int rop #I rasterop + +bool need_src, need_dst, rop_enable +short data, src_value, v_src, v_dst, pv +int segsize, opcode, x, i, np, rn_o, p +int d_src[LEN_PLRDES], d_dst[LEN_PLRDES] + +begin + need_src = R_NEED_SRC(rop) + need_dst = R_NEED_DST(rop) + opcode = R_OPCODE(rop) + data = R_DATA(rop) + + # Pixel value to be used if input mask is boolean. + if (src_maxval == 1) { + src_value = data + if (src_value <= 0) + src_value = dst_maxval + } + + # Advance to the desired position in the source list, discarding + # the unused ranges. The point XS may lie within a range or in a + # zero area of the input line. + + if (need_src) { + x = 1 + plr_init (rl_src, d_src) + do i = 1, ARB { + np = min (plr_nleft(d_src), xs - x) + plr_getseg (rl_src, d_src, np, v_src) + x = x + np + if (x >= xs || np == 0) + break + } + } + + # Advance through both the source and destination lists, extracting + # line segments which have a constant value in each input list; the + # values for the two lists may differ. Apply the given rasterop to + # the source and destination pixel values and write each line segment + # as a range to the output list. If the ranges in the two input lists + # differ (randomly overlap) then the output list will generally be + # more fragmented, i.e., have more ranges of constant value. As each + # output range is generated compare it with the previous range to see + # if they can be joined, as applying a rasterop may cause two different + # ranges to have the same value. + + x = 1 + rn_o = RL_FIRST + segsize = ds - 1 + rop_enable = false + plr_init (rl_dst, d_dst) + + do i = 1, ARB { + # Set up for the next segment (before, in, and after the region to + # which the ROP applies), when the current segment is exhausted. + + if (segsize <= 0) + if (!rop_enable) { + # Begin processing central region. + segsize = npix + rop_enable = true + if (segsize <= 0) + next + } else { + # Begin processing final region. + segsize = ARB + rop_enable = false + } + + # Determine the length of the next output segment. This is the + # largest segment of constant value formed by the intersection of + # the two lists. If bounds checking has been properly performed + # then it should not be possible to see nleft=zero on either input + # list. Note that zeroed regions are valid data here. + + np = min (segsize, plr_nleft(d_dst)) + if (need_src && rop_enable && plr_nleft(d_src) > 0) + np = min (np, plr_nleft(d_src)) + if (np <= 0) + break + + # Get the segment value and advance the line pointers. We must + # read the DST list whether or not we will use the data, since + # the list pointer must be advanced NPIX pixels so that we may + # copy the remainder of the list after the loop. + + plr_getseg (rl_dst, d_dst, np, v_dst) + if (rop_enable) { + # Get v_src. + if (need_src) { + v_src = 0 + if (plr_nleft (d_src) > 0) + plr_getseg (rl_src, d_src, np, v_src) + + if (R_NOTSRC(rop)) { + v_src = not (v_src) + if (src_maxval != 0) + v_src = and (int(v_src), src_maxval) + } + + if (v_src != 0 && src_maxval == 1) + v_src = src_value + } + + # Get v_dst. + if (need_dst) { + if (R_NOTDST(rop)) { + v_dst = not (v_dst) + if (dst_maxval != 0) + v_dst = and (int(v_dst), dst_maxval) + } + } + + # Apply the rasterop. + switch (opcode) { + case PIX_CLR: + pv = 0 + case PIX_SET: + pv = data + case PIX_SRC, PIX_NOTSRC: + pv = v_src + case PIX_DST, PIX_NOTDST: + pv = v_dst + case PIX_SRC_AND_DST, PIX_SRC_AND_NOTDST, PIX_NOTSRC_AND_DST: + pv = and (v_src, v_dst) + case PIX_SRC_OR_DST, PIX_SRC_OR_NOTDST, PIX_NOTSRC_OR_DST: + pv = or (v_src, v_dst) + case PIX_SRC_XOR_DST: + pv = xor (v_src, v_dst) + case PIX_NOT_SRC_AND_DST: + pv = not (and (v_src, v_dst)) + case PIX_NOT_SRC_OR_DST: + pv = not (or (v_src, v_dst)) + case PIX_NOT_SRC_XOR_DST: + pv = not (xor (v_src, v_dst)) + } + + # Mask the high bits to prevent negative values, or map int + # to bool for the case of a boolean output mask. + + if (dst_maxval == 1 && pv != 0) + pv = 1 + else if (dst_maxval > 1) + pv = and (int(pv), dst_maxval) + + } else + pv = v_dst + + # Output a nonzero range. + if (pv > 0) { + p = rn_o - 1 + if (p >= RL_FIRST && + pv == rl_out[3,p] && x == rl_out[1,p] + rl_out[2,p]) { + # Merge new range with previous one. + rl_out[2,p] = rl_out[2,p] + np + } else { + rl_out[1,rn_o] = x + rl_out[2,rn_o] = np + rl_out[3,rn_o] = pv + rn_o = rn_o + 1 + } + } + + x = x + np + segsize = segsize - np + } + + # Update the range list header. + call amovs (rl_dst, rl_out, (RL_FIRST - 1) * 3) + RL_LEN(rl_out) = rn_o - 1 +end diff --git a/sys/plio/zzdebug.x b/sys/plio/zzdebug.x new file mode 100644 index 00000000..0ff3cc47 --- /dev/null +++ b/sys/plio/zzdebug.x @@ -0,0 +1,1442 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <xwhen.h> +include <error.h> +include <ctype.h> +include <fset.h> +include <plset.h> +include <plio.h> + +task pltest = t_pltest, + script = t_script + +.help pltest +.nf ------------------------------------------------------------------------- +PLTEST -- PL package debug and test facility. + + Due to the complexity of the PL package, testing is performed using an +interactive interpreter which reads commands from the standard input. +All commands operate internally upon a set of four mask registers A-D, +and a set of ten vector registers V[0-9]. + + a,b,c,d - mask registers + v0,...,v9 - vector registers + +The following commands are defined: + + help # print command summary + timer # toggle timing of commands + run fname # read commands from a file + log [fname] # log commands in a file + clear # clear the screen + bye # all done (also EOF) + + create [mask] naxes axlen depth # create a new mask + load [mask] fname # load mask from file + save [mask] fname [title] # save mask in file + loadim [mask] image # load mask from image + saveim [mask] image [title] # save mask in image + erase [mask] [vs ve] # erase a mask or region + draw [mask] [vs ve] [>ofile] # draw mask or region of mask + + set [mask] # set reference mask + set [vector] i j k... # load vector register + show [vector] # print vector register + show [mask] [index] [ll] [rl] [>ofile] # print debug info for a mask + + box [mask] P1 P2 rop # draw a box + circle [mask] P1 r rop # draw a circle + line [mask] P1 P2 width rop # draw a line segment + point [mask] P1 rop # draw a point + polygon [mask] P1 ... PN rop # draw a polygon + + rop src [vs] dst [vs] [vn] rop # rasterop + stencil src [vs] dst [vs] stn [vs] [vn] rop # stencil + invert [mask] [vs [vn]] # invert a mask + + compare mask1 mask2 # compare two masks + rtest mask1 mask2 # range list conversion test + ptest mask1 mask2 # pixel array conversion test + secne [mask] vs ve # test if section not empty + secnc [mask] vs ve # test if section not constant + rio [mask] vs # test mask using random i/o + +Rasterops may be specified either as integer constants (any radix) or via +a simple symbolic notation, e.g.: "opcode+[value]". + +A mask may be examined in detail with SHOW, which calls pl_debug to decode +the contents of a mask. A graphic image of a mask may be drawn with DRAW, +which renders each pixel in the mask as a printable character. +.endhelp -------------------------------------------------------------------- + +define SZ_SBUF 512 # size limiting parameters +define DEF_MASKSIZE_X 75 +define DEF_MASKSIZE_Y 40 +define MAXKWLEN 20 +define MAXARGS 50 +define MAXMREG 4 +define MAXVREG 10 +define MAXINCL 10 +define WIDTH 80 + +define INT_ARG 1 # argument types +define STRING_ARG 2 +define VECTOR_ARG 3 +define MASK_ARG 4 + +define v_i argval[$1] # integer argument +define v_s sbuf[argval[$1]] # string argument +define v_si sbuf[argval[$1]+$2-1] # indexed string argument +define v_v v_reg[1,argval[$1]+1] # vector argument +define v_vi v_reg[$2,argval[$1]+1] # indexed vector argument +define v_m v_mask[argval[$1]] # mask argument + +define KW_BOX 1 # interpreter commands +define KW_BYE 2 +define KW_CIRCLE 3 +define KW_CLEAR 4 +define KW_COMPARE 5 +define KW_CREATE 6 +define KW_DRAW 7 +define KW_ERASE 8 +define KW_HELP 9 +# eol 10 +define KW_LINE 11 +define KW_POINT 12 +define KW_POLYGON 13 +define KW_LOAD 14 +define KW_LOADIM 15 +define KW_PTEST 16 +define KW_ROP 17 +define KW_RTEST 18 +define KW_RUN 19 +define KW_SAVE 20 +define KW_SAVEIM 21 +# eol 22 +define KW_SET 23 +define KW_SHOW 24 +define KW_SECNE 25 +define KW_SECNC 26 +define KW_RIO 27 +define KW_STENCIL 28 +define KW_INVERT 29 +define KW_TIMER 30 +define KW_LOG 31 + + +# PLTEST -- Test the PL package. Read and execute commands from the standard +# input until EOF or BYE is seen. + +procedure t_pltest() + +long time[2] +int x, y, r +bool timer, bval +int px[MAXARGS], py[MAXARGS], old_onint, width, mval +pointer pl, pl_1, pl_2, def_pl, pl_src, pl_dst, pl_stn, tty, plr +char cmd[SZ_LINE], kwname[SZ_FNAME], title[SZ_LINE], fname[SZ_FNAME] +int what, rop, v_arg, x1, x2, y1, y2, ip, op, ch, i, j, cmdlog, status +int opcode, save_fd[MAXINCL], in, fd, o_fd, maskno, depth, naxes, npts +int v1[PL_MAXDIM], v2[PL_MAXDIM], v3[PL_MAXDIM], v4[PL_MAXDIM], v[PL_MAXDIM] + +int plr_getpix(), pl_compare() +int fstati(), strdic(), open(), getline(), strncmp(), locpr() +pointer pl_create(), ttyodes(), plr_open() +bool pl_sectnotempty(), pl_sectnotconst() +extern onint() + +char sbuf[SZ_SBUF] +int nargs, argno, argtype[MAXARGS], argval[MAXARGS], s_op +int v_mask[MAXMREG], v_reg[PL_MAXDIM,MAXVREG], jmpbuf[LEN_JUMPBUF] +common /plzcom/ v_mask, v_reg, nargs, argno, argtype, argval, s_op, + jmpbuf, sbuf +define argerr_ 91 +define eof_ 92 + +string keywords "|box|bye|circle|clear|compare|create|draw|erase|help|\ + |line|point|polygon|load|loadim|ptest|rop|rtest|run|save|saveim|\ + |set|show|secne|secnc|rio|stencil|invert|timer|log|" + +begin + in = 0 + ip = 1 + fd = STDIN + cmdlog = 0 + cmd[ip] = EOS + timer = false + + # Initialize the mask registers. + v[1] = DEF_MASKSIZE_X + v[2] = DEF_MASKSIZE_Y + do i = 1, MAXMREG + v_mask[i] = pl_create (2, v, 7) + def_pl = v_mask[1] + + # Initialize the vector registers. + do i = 1, MAXVREG + call amovki (1, v_reg[1,i], PL_MAXDIM) + + # Main interpreter loop. + # --------------------------- + + call xwhen (X_INT, locpr(onint), old_onint) + call zsvjmp (jmpbuf, status) + + if (status != OK) { + # Clean up after an interrupt. + call xer_reset() + ip = 1; cmd[ip] = EOS + while (in > 0) { + call close (fd) + fd = save_fd[in] + in = in - 1 + } + } + + repeat { + # Get next command. + if (cmd[ip] == '\n' || cmd[ip] == '#' || cmd[ip] == EOS) { + # Prompt if reading from the standard input. + if (in == 0 && fstati (STDIN, F_REDIR) == NO) { + call putline (STDOUT, "* ") + call flush (STDOUT) + } + + # Handle EOF on the current command stream. + if (getline (fd, cmd) == EOF) { +eof_ if (in > 0) { + call close (fd) + fd = save_fd[in] + in = in - 1 + } else + break + } + + ip = 1 + } + + # Skip blank lines and comment lines. + for (ip=1; IS_WHITE(cmd[ip]) || cmd[ip] == ';'; ip=ip+1) + ; + if (cmd[ip] == '\n' || cmd[ip] == '#' || cmd[ip] == EOS) + next + + if (cmdlog != 0) + call putline (cmdlog, cmd) + + # Extract the keyword into the KWNAME buffer. Leave the input + # pointer positioned to the first char following the keyword. + + for (op=1; cmd[ip] != EOS && cmd[ip] != '\n'; ip=ip+1) { + ch = cmd[ip] + if (IS_ALNUM(ch) || ch == '?' || ch == '_') { + kwname[op] = ch + op = op + 1 + } else + break + } + kwname[op] = EOS + + # Look up the keyword in the dictionary. If not found ring the + # bell, but do not quit. + + if (kwname[1] == '?') + opcode = KW_HELP + else + opcode = strdic (kwname, kwname, MAXKWLEN, keywords) + if (opcode <= 0) { + call eprintf ("unknown command\007\n") + call flush (STDERR) + ip=1; cmd[ip] = EOS + next + } + + # Parse the argument list. + call parse_args (cmd, ip) + + # Process the command. + # ------------------------- + + switch (opcode) { + case KW_BYE: + goto eof_ + + case KW_LOG: + # Enable/Disable command logging. + + if (cmdlog == 0) { + if (nargs >= 1 && argtype[argno] == STRING_ARG) + cmdlog = open (v_s(argno), APPEND, TEXT_FILE) + else + cmdlog = open ("zzdebug.log", APPEND, TEXT_FILE) + call eprintf ("command spooling enabled\n") + call fprintf (cmdlog, "# --- begin ---\n") + } else { + call close (cmdlog) + cmdlog = 0 + call eprintf ("command spooling disabled\n") + } + + case KW_POINT: + # Draw a point. + + # Get mask. + pl = def_pl + if (argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get coords of point. + if (argtype[argno] == VECTOR_ARG) { + # Coords given as vectors. + x1 = v_vi(argno,1) + y1 = v_vi(argno,2) + argno = argno + 1 + } else { + # Coords given explicitly. + do i = 1, 2 + if (argtype[argno+i-1] != INT_ARG) + goto argerr_ + + x1 = v_i(argno); argno = argno + 1 + y1 = v_i(argno); argno = argno + 1 + } + + # Get rop. + if (argno <= nargs) { + if (argtype[argno] != INT_ARG) + goto argerr_ + rop = v_i(argno); argno = argno + 1 + } else + rop = or (PIX_SRC, PIX_DST) + PIX_VALUE('1') + + # Perform the operation. + if (timer) + call sys_mtime (time) + call pl_point (pl, x1, y1, rop) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_BOX: + # Draw a box. + + # Get mask. + pl = def_pl + if (argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get corner coords of box. + if (argtype[argno] == VECTOR_ARG) { + # Coords given as vectors. + x1 = v_vi(argno,1) + y1 = v_vi(argno,2) + argno = argno + 1 + if (argtype[argno] != VECTOR_ARG) + goto argerr_ + x2 = v_vi(argno,1) + y2 = v_vi(argno,2) + argno = argno + 1 + + } else { + # Coords given explicitly. + do i = 1, 4 + if (argtype[argno+i-1] != INT_ARG) + goto argerr_ + + x1 = v_i(argno); argno = argno + 1 + y1 = v_i(argno); argno = argno + 1 + x2 = v_i(argno); argno = argno + 1 + y2 = v_i(argno); argno = argno + 1 + } + + # Get rop. + if (argno <= nargs) { + if (argtype[argno] != INT_ARG) + goto argerr_ + rop = v_i(argno); argno = argno + 1 + } else + rop = or (PIX_SRC, PIX_DST) + PIX_VALUE('2') + + # Perform the operation. + if (timer) + call sys_mtime (time) + call pl_box (pl, x1, y1, x2, y2, rop) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_LINE: + # Draw a line of arbitrary orientation and width. + + # Get mask. + pl = def_pl + if (argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get endpoints of line. + if (argtype[argno] == VECTOR_ARG) { + # Coords given as vectors. + x1 = v_vi(argno,1) + y1 = v_vi(argno,2) + argno = argno + 1 + if (argtype[argno] != VECTOR_ARG) + goto argerr_ + x2 = v_vi(argno,1) + y2 = v_vi(argno,2) + argno = argno + 1 + + } else { + # Coords given explicitly. + do i = 1, 4 + if (argtype[argno+i-1] != INT_ARG) + goto argerr_ + + x1 = v_i(argno); argno = argno + 1 + y1 = v_i(argno); argno = argno + 1 + x2 = v_i(argno); argno = argno + 1 + y2 = v_i(argno); argno = argno + 1 + } + + # Get line width. + if (argno <= nargs) { + if (argtype[argno] != INT_ARG) + goto argerr_ + width = v_i(argno); argno = argno + 1 + } else + width = 1 + + # Get rop. + if (argno <= nargs) { + if (argtype[argno] != INT_ARG) + goto argerr_ + rop = v_i(argno); argno = argno + 1 + } else + rop = or (PIX_SRC, PIX_DST) + PIX_VALUE('4') + + # Perform the operation. + if (timer) + call sys_mtime (time) + call pl_line (pl, x1, y1, x2, y2, width, rop) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_CIRCLE: + # Draw a circle. + + # Get mask. + pl = def_pl + if (argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get center coords and radius of circle. + if (argtype[argno] == VECTOR_ARG) { + # Center coords given as a vector. + x = v_vi(argno,1) + y = v_vi(argno,2) + argno = argno + 1 + + } else { + # Center coords given explicitly. + do i = 1, 2 + if (argtype[argno+i-1] != INT_ARG) + goto argerr_ + + x = v_i(argno); argno = argno + 1 + y = v_i(argno); argno = argno + 1 + } + + if (argtype[argno] != INT_ARG) + goto argerr_ + r = v_i(argno); argno = argno + 1 + + # Get rop. + if (argno <= nargs) { + if (argtype[argno] != INT_ARG) + goto argerr_ + rop = v_i(argno); argno = argno + 1 + } else + rop = or (PIX_SRC, PIX_DST) + PIX_VALUE('Q') + + # Perform the operation. + if (timer) + call sys_mtime (time) + call pl_circle (pl, x, y, r, rop) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_POLYGON: + # Draw a polygon. + + # Get mask. + pl = def_pl + if (argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get the coordinates of the polygon. + for (npts=0; argno <= nargs; ) { + npts = npts + 1 + + if (argtype[argno] == VECTOR_ARG) { + # Coords of point given as a vector. + px[npts] = v_vi(argno,1) + py[npts] = v_vi(argno,2) + argno = argno + 1 + + } else if (argtype[argno] == INT_ARG && + argtype[argno+1] == INT_ARG) { + + # Center coords given explicitly. + px[npts] = v_i(argno); argno = argno + 1 + py[npts] = v_i(argno); argno = argno + 1 + } + } + + # Get rop. + if (argno <= nargs) { + if (argtype[argno] != INT_ARG) + goto argerr_ + rop = v_i(argno); argno = argno + 1 + } else + rop = or (PIX_SRC, PIX_DST) + PIX_VALUE('R') + + # Perform the operation. + if (timer) + call sys_mtime (time) + call pl_polygon (pl, px, py, npts, rop) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_CLEAR: + # Clear the screen. + tty = ttyodes ("terminal") + call ttyclear (STDOUT, tty) + call ttycdes (tty) + + case KW_COMPARE: + # Compare two masks. + if (nargs < 2) + goto argerr_ + + # Get mask 1. + if (argtype[argno] == MASK_ARG) { + pl_1 = v_m(argno) + argno = argno + 1 + } else + goto argerr_ + + # Get mask 2. + if (argtype[argno] == MASK_ARG) { + pl_2 = v_m(argno) + argno = argno + 1 + } else + goto argerr_ + + # Perform the operation. + if (timer) + call sys_mtime (time) + status = pl_compare (pl_1, pl_2, STDOUT) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_CREATE: + # Create a new, emtpy mask of the given size and depth. + + # Get mask. + maskno = 1 + if (argtype[argno] == MASK_ARG) { + maskno = v_i(argno) + argno = argno + 1 + } + + # Get naxes. + if (argtype[argno] != INT_ARG) + goto argerr_ + naxes = v_i(argno); argno = argno + 1 + + # Get mask size. + if (argtype[argno] == VECTOR_ARG) { + # Mask size given as vector. + call amovi (v_v(argno), v1, PL_MAXDIM) + argno = argno + 1 + } else { + # Mask size given explicitly. + do i = 1, naxes { + if (argtype[argno+i-1] != INT_ARG) + goto argerr_ + v1[i] = v_i(argno) + argno = argno + 1 + } + } + + # Get mask depth. + if (argtype[argno] != INT_ARG) + depth = 1 + else { + depth = v_i(argno) + argno = argno + 1 + } + + # Perform the operation. + if (timer) + call sys_mtime (time) + call pl_close (v_mask[maskno]) + v_mask[maskno] = pl_create (naxes, v1, depth) + def_pl = v_mask[maskno] + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_DRAW: + # Draw a mask or region of a mask on the screen. + + # Get mask. + pl = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get vector coords of region to be drawn. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v1, PL_MAXDIM) + argno = argno + 1 + } else + call amovki (1, v1, PL_MAXDIM) + + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v2, PL_MAXDIM) + argno = argno + 1 + } else + call amovi (PL_AXLEN(pl,1), v2, PL_MAXDIM) + + # Get output stream. + o_fd = STDOUT + if (argtype[argno] == STRING_ARG) { + if (v_si(argno,1) == '>') { + # Write output to a file. + if (v_si(argno,2) == '>') { + iferr (o_fd = open (v_si(argno,3), + APPEND, TEXT_FILE)) { + call erract (EA_WARN) + o_fd = STDOUT + } + } else { + iferr (o_fd = open (v_si(argno,2), + NEW_FILE, TEXT_FILE)) { + call erract (EA_WARN) + o_fd = STDOUT + } + } + } else { + call eprintf ("unknown option `%s'\n") + call pargstr (v_s(argno)) + } + argno = argno + 1 + } + + # Perform the operation. + call pl_asciidump (pl, v1, v2, o_fd) + + if (o_fd != STDOUT) + call close (o_fd) + + case KW_ERASE: + # Erase a mask, or a region of a mask. + + # Get mask. + pl = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get vector coords of region to be erased. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v1, PL_MAXDIM) + argno = argno + 1 + } else + call amovki (1, v1, PL_MAXDIM) + + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v2, PL_MAXDIM) + argno = argno + 1 + } else + call amovi (PL_AXLEN(pl,1), v2, PL_MAXDIM) + + # Perform the operation. + if (timer) + call sys_mtime (time) + if (nargs <= 1) + call pl_clear (pl) + else + call pl_rop (NULL, 0, pl, v1, v2, PIX_CLR) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_HELP: + # Print a command summary. + call print_help (STDOUT) + + case KW_RUN: + # Read commands from a file. + if (nargs < 1 || argtype[argno] != STRING_ARG) + goto argerr_ + + in = in + 1 + if (in > MAXINCL) + call error (1, "too many nested run files\n") + save_fd[in] = fd + iferr (fd = open (v_s(argno), READ_ONLY, TEXT_FILE)) { + call erract (EA_WARN) + fd = save_fd[in] + in = in - 1 + } + + case KW_SET: + # Set the value of a mask or vector register. + if (nargs < 1) { + goto argerr_ + + } else if (argtype[argno] == MASK_ARG) { + # Set the default mask. + def_pl = v_m(argno) + maskno = v_i(argno) + + } else if (argtype[argno] == VECTOR_ARG) { + # Set a vector register. + v_arg = argno + argno = argno + 1 + + do i = 1, PL_MAXDIM + if (argno <= nargs && argtype[argno] == INT_ARG) { + v[i] = v_i(argno) + argno = argno + 1 + } else + v[i] = 1 + + call amovi (v, v_v(v_arg), PL_MAXDIM) + } + + case KW_SHOW: + # Print information about a mask or vector register. + + if (nargs < 1 || argtype[argno] == MASK_ARG) { + # Print information about a mask. + + if (nargs < 1) + pl = def_pl + else { + pl = v_m(argno) + argno = argno + 1 + } + + o_fd = STDOUT + + # Process option selects. + what = PD_SUMMARY + while (argno <= nargs && argtype[argno] == STRING_ARG) { + if (strncmp (v_s(argno), "i", 1) == 0) { + what = or (what, PD_INDEX) + } else if (strncmp (v_s(argno), "ll", 2) == 0) { + what = or (what, PD_LLOUT) + } else if (strncmp (v_s(argno), "rl", 2) == 0) { + what = or (what, PD_RLOUT) + } else if (strncmp (v_s(argno), "lh", 2) == 0) { + what = or (what, PD_LHDR) + + } else if (v_si(argno,1) == '>') { + # Write output to a file. + if (v_si(argno,2) == '>') { + iferr (o_fd = open (v_si(argno,3), + APPEND, TEXT_FILE)) { + call erract (EA_WARN) + o_fd = STDOUT + } + } else { + iferr (o_fd = open (v_si(argno,2), + NEW_FILE, TEXT_FILE)) { + call erract (EA_WARN) + o_fd = STDOUT + } + } + } else { + call eprintf ("unknown option `%s'\n") + call pargstr (v_s(argno)) + } + argno = argno + 1 + } + + # Perform the operation. + call pl_debug (pl, o_fd, WIDTH, what) + if (o_fd != STDOUT) + call close (o_fd) + + } else if (argtype[argno] == VECTOR_ARG) { + # Print the value of a vector register. + call printf ("v%d: ") + call pargi (v_i(argno)) + do i = 1, PL_MAXDIM { + call printf (" %d") + call pargi (v_vi(argno,i)) + } + call printf ("\n") + + } else { + # Print the value of all vector registers. + do j = 1, MAXVREG { + call printf ("v%d: ") + call pargi (j-1) + do i = 1, PL_MAXDIM { + call printf (" %d") + call pargi (v_reg(i,j)) + } + call printf ("\n") + } + } + + case KW_LOAD: + # Load a mask from a file. + + # Get mask to be loaded. + pl = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get mask filename. + if (argno > nargs || argtype[argno] != STRING_ARG) + goto argerr_ + + # Perform the operation. + if (timer) + call sys_mtime (time) + iferr (call pl_loadf (pl, v_s(argno), title, SZ_LINE)) + call erract (EA_WARN) + else if (title[1] != EOS) { + call printf ("mask: %s\n") + call pargstr (title) + call flush (STDOUT) + } + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_SAVE: + # Save a mask in a file. + + # Get mask to be saved. + pl = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get mask filename. + if (argno > nargs || argtype[argno] != STRING_ARG) + goto argerr_ + else { + call strcpy (v_s(argno), fname, SZ_FNAME) + argno = argno + 1 + } + + # Get title string. + if (argno <= nargs && argtype[argno] == STRING_ARG) { + call strcpy (v_s(argno), title, SZ_LINE) + argno = argno + 1 + } + + # Perform the operation. + if (timer) + call sys_mtime (time) + iferr (call pl_savef (pl, fname, title, 0)) + call erract (EA_WARN) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_LOADIM: + # Load a mask from an image. + + # Get mask to be loaded. + pl = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get image section. + if (argno > nargs || argtype[argno] != STRING_ARG) + goto argerr_ + + # Perform the operation. + if (timer) + call sys_mtime (time) + iferr (call pl_loadim (pl, v_s(argno), title, SZ_LINE)) + call erract (EA_WARN) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_SAVEIM: + # Save a mask in an image. + + # Get mask to be saved. + pl = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get output image name. + if (argno > nargs || argtype[argno] != STRING_ARG) + goto argerr_ + else { + call strcpy (v_s(argno), fname, SZ_FNAME) + argno = argno + 1 + } + + # Get title string. + if (argno <= nargs && argtype[argno] == STRING_ARG) { + call strcpy (v_s(argno), title, SZ_LINE) + argno = argno + 1 + } + + # Perform the operation. + if (timer) + call sys_mtime (time) + iferr (call pl_saveim (pl, fname, title, 0)) + call erract (EA_WARN) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_ROP: + # General rasterop operation. + + # Get source mask. + pl_src = def_pl + if (argtype[argno] == MASK_ARG) { + pl_src = v_m(argno) + argno = argno + 1 + } + + # Get start vector in source mask. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v1, PL_MAXDIM) + argno = argno + 1 + } else + call amovki (1, v1, PL_MAXDIM) + + # Get destination mask. + pl_dst = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl_dst = v_m(argno) + argno = argno + 1 + } + + # Get start vector in destination mask. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v2, PL_MAXDIM) + argno = argno + 1 + } else + call amovki (1, v2, PL_MAXDIM) + + # Get vector defining size of region to be modified. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v3, PL_MAXDIM) + argno = argno + 1 + } else + call amovi (PL_AXLEN(pl_dst,1), v3, PL_MAXDIM) + + # Get rop. + if (argno <= nargs) { + if (argtype[argno] != INT_ARG) + goto argerr_ + rop = v_i(argno); argno = argno + 1 + } else + rop = PIX_SRC + + # Perform the operation. + if (timer) + call sys_mtime (time) + call pl_rop (pl_src, v1, pl_dst, v2, v3, rop) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_STENCIL: + # Rasterop operation though a stencil mask. + + # Get source mask. + pl_src = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl_src = v_m(argno) + argno = argno + 1 + } + + # Get start vector in source mask. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v1, PL_MAXDIM) + argno = argno + 1 + } else + call amovki (1, v1, PL_MAXDIM) + + # Get destination mask. + pl_dst = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl_dst = v_m(argno) + argno = argno + 1 + } + + # Get start vector in destination mask. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v2, PL_MAXDIM) + argno = argno + 1 + } else + call amovki (1, v2, PL_MAXDIM) + + # Get stencil mask. + pl_stn = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl_stn = v_m(argno) + argno = argno + 1 + } + + # Get start vector in stencil mask. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v3, PL_MAXDIM) + argno = argno + 1 + } else + call amovki (1, v3, PL_MAXDIM) + + # Get vector defining size of region to be modified. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v4, PL_MAXDIM) + argno = argno + 1 + } else + call amovi (PL_AXLEN(pl_dst,1), v4, PL_MAXDIM) + + # Get rop. + if (argno <= nargs) { + if (argtype[argno] != INT_ARG) + goto argerr_ + rop = v_i(argno); argno = argno + 1 + } else { + call eprintf ("no rop specified - copying src to dst\n") + rop = PIX_SRC + } + + # Perform the operation. + if (timer) + call sys_mtime (time) + call pl_stencil (pl_src, v1, pl_dst, v2, pl_stn, v3, v4, rop) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_INVERT: + # Invert a mask. + + # Get mask. + pl_src = def_pl + if (argtype[argno] == MASK_ARG) { + pl_src = v_m(argno) + argno = argno + 1 + } + pl_dst = pl_src + + # Get start vector in mask. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v1, PL_MAXDIM) + argno = argno + 1 + } else + call amovki (1, v1, PL_MAXDIM) + + # Get vector defining size of region to be modified. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v2, PL_MAXDIM) + argno = argno + 1 + } else + call amovi (PL_AXLEN(pl_dst,1), v2, PL_MAXDIM) + + # Perform the operation. + if (timer) + call sys_mtime (time) + rop = PIX_NOT(PIX_SRC) + call pl_rop (pl_src, v1, pl_dst, v1, v2, rop) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_PTEST, KW_RTEST: + # Line list to pixel array or range list conversion test. + if (nargs < 2) + goto argerr_ + + # Get mask 1. + if (argtype[argno] == MASK_ARG) { + pl_1 = v_m(argno) + argno = argno + 1 + } else + goto argerr_ + + # Get mask 2. + if (argtype[argno] == MASK_ARG) { + pl_2 = v_m(argno) + argno = argno + 1 + } else + goto argerr_ + + # Perform the operation. + if (timer) + call sys_mtime (time) + call conv_test (pl_1, pl_2, STDOUT, opcode) + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_SECNE: + # Test if a section of a mask is not empty. + + # Get mask. + pl = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get vector coords of region to be erased. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v1, PL_MAXDIM) + argno = argno + 1 + } else + call amovki (1, v1, PL_MAXDIM) + + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v2, PL_MAXDIM) + argno = argno + 1 + } else + call amovi (PL_AXLEN(pl,1), v2, PL_MAXDIM) + + # Perform the operation. + if (timer) + call sys_mtime (time) + + bval = pl_sectnotempty (pl, v1, v2, 2) + call printf ("pl_sectnotempty -> %b (mask is %s)\n") + call pargb (bval) + if (bval) + call pargstr ("not empty") + else + call pargstr ("empty") + + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_SECNC: + # Test if a section of a mask is not constant. + + # Get mask. + pl = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get vector coords of region to be erased. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v1, PL_MAXDIM) + argno = argno + 1 + } else + call amovki (1, v1, PL_MAXDIM) + + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v2, PL_MAXDIM) + argno = argno + 1 + } else + call amovi (PL_AXLEN(pl,1), v2, PL_MAXDIM) + + # Perform the operation. + if (timer) + call sys_mtime (time) + + call printf ("pl_sectnotconst -> ") + if (pl_sectnotconst (pl, v1, v2, 2, mval)) + call printf ("true (mask is not constant)\n") + else { + call printf ("false (mask is constant, value=%d)\n") + call pargi (mval) + } + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_RIO: + # Test access to a mask using random io (plr_getpix). + + # Get mask. + pl = def_pl + if (nargs >= 1 && argtype[argno] == MASK_ARG) { + pl = v_m(argno) + argno = argno + 1 + } + + # Get vector coords of region to be tested. + if (argtype[argno] == VECTOR_ARG) { + call amovi (v_v(argno), v1, PL_MAXDIM) + argno = argno + 1 + } else + call amovki (1, v1, PL_MAXDIM) + + # Perform the operation. + if (timer) + call sys_mtime (time) + + call amovki (1, v, PL_MAXDIM) + plr = plr_open (pl, v, 0) + call printf ("mask pixel [%d,%d] has value %d\n") + call pargi (v1[1]) + call pargi (v1[2]) + call pargi (plr_getpix (plr, v1[1], v1[2])) + call plr_close (plr) + + if (timer) + call sys_ptime (STDOUT, "", time) + + case KW_TIMER: + if (timer) { + call printf ("timer off\n") + timer = false + } else { + call printf ("timer on\n") + timer = true + } + + default: + # Unrecognized command. + call eprintf ("unknown switch\007\n") + call flush (STDERR) + } + + call flush (STDOUT) + if (cmdlog != 0) + call flush (cmdlog) + next +argerr_ + call eprintf ("invalid argument list\n") + } + + call zxwhen (X_INT, old_onint, status) + if (cmdlog != 0) + call close (cmdlog) + + do i = 1, MAXMREG + call pl_close (v_mask[i]) +end + + +# ONINT -- Interrupt handler. + +procedure onint (signal, next_handler) + +int signal #I signal code +int next_handler #O epa of next handler + +char sbuf[SZ_SBUF] +int nargs, argno, argtype[MAXARGS], argval[MAXARGS], s_op +int v_mask[MAXMREG], v_reg[PL_MAXDIM,MAXVREG], jmpbuf[LEN_JUMPBUF] +common /plzcom/ v_mask, v_reg, nargs, argno, argtype, argval, s_op, + jmpbuf, sbuf + +begin + call fseti (STDOUT, F_CANCEL, OK) + call eprintf ("interrupt!\007\n") + call zdojmp (jmpbuf, signal) +end + + +# PARSE_ARGS -- Parse the argument list to an interpreter command, leaving +# the decoded arguments in the interpreter common, and returning the number +# of arguments as the function value. + +procedure parse_args (args, ip) + +char args[ARB] # argument list +int ip # pointer into argument list + +double dval +int nchars, junk, i +int ctowrd(), stridx(), gctod(), strlen() + +char sbuf[SZ_SBUF] +int nargs, argno, argtype[MAXARGS], argval[MAXARGS], s_op +int v_mask[MAXMREG], v_reg[PL_MAXDIM,MAXVREG], jmpbuf[LEN_JUMPBUF] +common /plzcom/ v_mask, v_reg, nargs, argno, argtype, argval, s_op, + jmpbuf, sbuf + +begin + s_op = 1 + argno = 1 + nargs = 0 + + do i = 1, MAXARGS + argtype[i] = 0 + + # Get next token. + junk = ctowrd (args, ip, sbuf[s_op], SZ_SBUF-s_op) + nchars = strlen (sbuf[s_op]) + + while (nchars > 0) { + nargs = nargs + 1 + if (nargs > MAXARGS) + call error (1, "too many arguments") + + if (nchars == 1 && sbuf[s_op] == '=') { + # Discard assignment operator. + nargs = nargs - 1 + + } else if (nchars == 1 && stridx (sbuf[s_op], "abcd") > 0) { + # Mask register. + argval[nargs] = stridx (sbuf[s_op], "abcd") + argtype[nargs] = MASK_ARG + + } else if (nchars == 2 && sbuf[s_op] == 'v' && + # Vector register. + IS_DIGIT(sbuf[s_op+1])) { + argval[nargs] = TO_INTEG(sbuf[s_op+1]) + argtype[nargs] = VECTOR_ARG + + } else if (IS_DIGIT (sbuf[s_op])) { + # Get an integer constant. + i=1; nchars = gctod (sbuf[s_op], i, dval) + argval[nargs] = nint(dval) + argtype[nargs] = INT_ARG + + # Handle the notation "opcode+value", for rasterops. + if (sbuf[s_op+i-1] == '+') { + i=i+1; nchars = gctod (sbuf[s_op], i, dval) + argval[nargs] = argval[nargs] + PIX_VALUE(nint(dval)) + } + + } else { + # String constant. + argval[nargs] = s_op + argtype[nargs] = STRING_ARG + s_op = s_op + nchars + 1 + } + + while (IS_WHITE(args[ip])) + ip = ip + 1 + if (args[ip] == ';' || args[ip] == '\n') { + ip = ip + 1 + break + } + + # Get next token. + junk = ctowrd (args, ip, sbuf[s_op], SZ_SBUF-s_op) + nchars = strlen (sbuf[s_op]) + } +end + + +# CONV_TEST -- Test the line list to pixel array or range list conversion +# routines. + +procedure conv_test (pl_1, pl_2, fd, opcode) + +pointer pl_1 #I input mask +pointer pl_2 #I output mask +int fd #I output file, for reporting errors +int opcode #I KW_[PR]TEST + +begin + call fprintf (fd, "conv_test called\n") +end + + +# PRINT_HELP -- Print the PL test interpreter commands help summary. + +procedure print_help (fd) + +int fd #I output file + +begin + call fprintf (fd, "help%48t# print command summary\n") + call fprintf (fd, "timer%48t# toggle timing of commands\n") + call fprintf (fd, "run fname%48t# read commands from a file\n") + call fprintf (fd, "log [fname]%48t# log commands in a file\n") + call fprintf (fd, "clear%48t# clear the screen\n") + call fprintf (fd, "bye%48t# all done (also EOF)\n\n") + call fprintf (fd, + "create [mask] naxes axlen [depth]%48t# create a new mask\n") + call fprintf (fd, "load [mask] fname%48t# load mask from file\n") + call fprintf (fd, "save [mask] fname%48t# save mask in file\n") + call fprintf (fd, "loadim [mask] image%48t# load mask from image\n") + call fprintf (fd, "saveim [mask] image%48t# save mask in image\n") + call fprintf (fd, "erase [mask] [vs ve]%48t# erase a mask or region\n") + call fprintf (fd, + "draw [mask] [vs ve] [>ofile]%48t# draw mask or region of mask\n\n") + call fprintf (fd, "set [mask]%48t# set reference mask\n") + call fprintf (fd, "set [vector] i j k...%48t# load vector register\n") + call fprintf (fd, "show [vector]%48t# print vector register\n") + call fprintf (fd, +"show [mask] [index] [ll] [rl] [>ofile]%48t# print debug info for a mask\n\n") + call fprintf (fd, "box P1 P2 rop%48t# draw a box\n") + call fprintf (fd, "circle P1 r rop%48t# draw a circle\n \n") + call fprintf (fd, + "line [mask] P1 P2 width rop%48t# draw a line segment\n") + call fprintf (fd, "point [mask] P1 rop%48t# draw a point\n") + call fprintf (fd, "polygon [mask] P1 ... PN rop%48t# draw a polygon\n") + call fprintf (fd, "rop src [vs] dst [vs] [vn] rop%48t# rasterop\n") + call fprintf (fd, + "stencil src [vs] dst [vs] stn [vs] [vn] rop%48t# stencil\n \n") + call fprintf (fd, "compare mask1 mask2%48t# compare two masks\n") + call fprintf (fd, "rtest mask1 mask2%48t# range list conversion test\n") + call fprintf (fd, + "ptest mask1 mask2%48t# pixel array conversion test\n") + call fprintf (fd, "secne [mask] [vs ve]%48t# test section not empty\n") + call fprintf (fd, "rio [mask] [vs]%48t# test mask using random i/o\n") +end + + +# SCRIPT -- Make a PLIO drawing script suitable to input to PLTEST above. + +procedure t_script() + +int ncmds, seed, i +int xo, yo, xs, ys, x, y, r +int clgeti() +real urand() + +begin + ncmds = clgeti ("ncmds") + + xo = 50; xs = 1024 - 100 + yo = 50; ys = 1024 - 100 + + seed = 5 + + do i = 1, ncmds { + x = urand(seed) * xs + xo + y = urand(seed) * ys + yo + r = urand(seed) * 40 + + call printf ("circle %d %d %d %d\n") + call pargi (x) + call pargi (y) + call pargi (r) + call pargi (PIX_SET + PIX_VALUE(mod(i,256))) + + call printf ("box %d %d %d %d %d\n") + call pargi (x - r) + call pargi (y - r) + call pargi (x + r) + call pargi (y + r) + call pargi (or(PIX_SRC,PIX_DST) + PIX_VALUE(mod(i*2,256))) + + call printf ("point %d %d %d\n") + call pargi (x) + call pargi (y) + call pargi (PIX_CLR + PIX_VALUE(mod(i*4,256))) + } +end diff --git a/sys/plio/zzlib.x b/sys/plio/zzlib.x new file mode 100644 index 00000000..fe21d849 --- /dev/null +++ b/sys/plio/zzlib.x @@ -0,0 +1,64 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <plio.h> + +# PL_CHKFREE -- Verify that the count of free space in the linelist is +# correct. (DEBUG TOOL). + +procedure pl_chkfree (pl, msg) + +pointer pl #I mask descriptor +char msg[ARB] #I message to be printed if error occurs + +pointer o_lp +short nref[8192], nl +int used, free, nused, nfree, b_len, i + +begin + used = 0; nused = 0 + free = 0; nfree = 0 + + # Count the space in the active line lists. + nl = 0 + for (i=0; i < PL_LLOP(pl); i=i+b_len) { + o_lp = Ref (pl, i) + b_len = LP_BLEN(o_lp) + + nl = nl + 1 + nref[nl] = LP_NREF(o_lp) + + if (LP_NREF(o_lp) < 0) { + call eprintf ("lineoff %d, nref = %d\n") + call pargi (i) + call pargi (LP_NREF(o_lp)) + free = free + b_len + nfree = nfree + 1 + } else if (i == PL_EMPTYLINE || LP_NREF(o_lp) > 0) { + used = used + b_len + nused = nused + 1 + } else { + free = free + b_len + nfree = nfree + 1 + } + } + + if (free != PL_LLFREE(pl)) { + call eprintf ("CHKFREE (%s): used=%d,%d, free=%d,%d, ") + call pargstr (msg) + call pargi (used) + call pargi (nused) + call pargi (free) + call pargi (nfree) + call eprintf ("PL_LLFREE=%d, OP-FREE=%d\n") + call pargi (PL_LLFREE(pl)) + call pargi (PL_LLOP(pl) - PL_LLFREE(pl)) + + do i = 1, nl { + call eprintf ("%4d") + call pargs (nref[i]) + if (mod (i,19) == 0) + call eprintf ("\n") + } + call eprintf ("\n") + } +end diff --git a/sys/plio/zzsum.x b/sys/plio/zzsum.x new file mode 100644 index 00000000..2e6097f9 --- /dev/null +++ b/sys/plio/zzsum.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <pmset.h> + +task sum = t_sum + +# SUM -- Sum the image pixels lying within the given mask. + +procedure t_sum() + +char image[SZ_FNAME] # input data image +char mask[SZ_FNAME] # image mask + +int npix, mval, totpix, m_flags +long v[PM_MAXDIM] +pointer im, mp, pp +real sum + +bool clgetb() +real asumr() +int mio_glsegr() +pointer immap(), mio_open() + +begin + call clgstr ("image", image, SZ_FNAME) + call clgstr ("mask", mask, SZ_FNAME) + m_flags = 0 + if (clgetb ("invert")) + m_flags = INVERT_MASK + + im = immap (image, READ_ONLY, 0) + mp = mio_open (mask, m_flags, im) + + sum = 0; totpix = 0 + while (mio_glsegr (mp, pp, mval, v, npix) != EOF) { + sum = sum + asumr (Memr[pp], npix) + totpix = totpix + npix + } + + call mio_close (mp) + call imunmap (im) + + call printf ("%d pixels, sum=%g, mean=%g\n") + call pargi (totpix) + call pargr (sum) + if (totpix > 0) + call pargr (sum / totpix) + else + call pargr (INDEF) +end |